ソースを参照

style: 美化项目中的所有代码

zhupei 1 年間 前
コミット
587ba4f5ae
100 ファイル変更6064 行追加5917 行削除
  1. 1 1
      .editorconfig
  2. 6 6
      .eslintrc.js
  3. 3 1
      .prettierignore
  4. 6 6
      .prettierrc
  5. 34 39
      .vscode/settings.json
  6. 1 1
      README.md
  7. 11 11
      index.html
  8. 69 62
      src/App.vue
  9. 5 5
      src/ajax/api/agent.js
  10. 1 1
      src/ajax/api/document.js
  11. 1 1
      src/ajax/api/knowledge.js
  12. 1 1
      src/ajax/api/message.js
  13. 17 17
      src/ajax/api/user.js
  14. 7 7
      src/ajax/document.js
  15. 6 6
      src/ajax/index.js
  16. 11 11
      src/ajax/replace-proxy-url.js
  17. 3 16
      src/assets/base.css
  18. 5 5
      src/assets/main.css
  19. 90 90
      src/components/DialogFeedback.vue
  20. 908 906
      src/components/DialogWrap.vue
  21. 135 122
      src/components/Directory.vue
  22. 146 126
      src/components/DocumentCards.vue
  23. 183 180
      src/components/DocumentReportFooter.vue
  24. 112 68
      src/components/History.vue
  25. 41 42
      src/components/Introduction.vue
  26. 118 115
      src/components/MessageInput.vue
  27. 95 95
      src/components/NormalCards.vue
  28. 12 12
      src/components/PictureFooter.vue
  29. 105 96
      src/components/PictureMessageInput.vue
  30. 135 145
      src/components/PictureUpload.vue
  31. 32 31
      src/components/ProjectIntro.vue
  32. 67 69
      src/components/RecordList.vue
  33. 43 40
      src/components/Slider.vue
  34. 22 22
      src/components/ToggleBtn.vue
  35. 28 30
      src/components/TopBar.vue
  36. 5 7
      src/components/answer-effect/RootImage.vue
  37. 16 10
      src/components/answer-effect/RootRefference.vue
  38. 46 46
      src/components/answer-effect/apply-image-display.js
  39. 50 50
      src/components/answer-effect/apply-refference-popover.js
  40. 19 19
      src/components/answer-effect/effect-image-display.js
  41. 23 23
      src/components/answer-effect/effect-refference-flag.js
  42. 57 57
      src/components/answer-effect/format-anwser-string.js
  43. 9 9
      src/components/answer-effect/marked-lib.js
  44. 59 59
      src/components/answer-effect/temp-history.js
  45. 3 3
      src/components/answer-effect/test.marked.js
  46. 66 65
      src/components/answer-pictures/AnwserInfo.vue
  47. 9 10
      src/components/answer-pictures/AnwserPictureLoading.vue
  48. 70 80
      src/components/answer-pictures/AnwserPictureResult.vue
  49. 23 24
      src/components/answer-refference/AsideImage.vue
  50. 66 59
      src/components/answer-refference/RefferenceFlag.vue
  51. 33 31
      src/components/btn-iframe-chujuan/BtnIframeChujuan.vue
  52. 33 31
      src/components/btn-iframe-comfyui/BtnIframeComfyui.vue
  53. 21 21
      src/components/btn-manage-doc/BtnMangeDoc.vue
  54. 50 54
      src/components/dialog-wrap/Answer.vue
  55. 7 8
      src/components/dialog-wrap/ClientUserAvatar.vue
  56. 40 40
      src/components/dialog-wrap/CodeDisplay.vue
  57. 107 101
      src/components/dialog-wrap/DocRefItem.vue
  58. 92 92
      src/components/dialog-wrap/Question.vue
  59. 13 10
      src/components/dialog-wrap/Suggestion.vue
  60. 9 9
      src/components/dialog-wrap/format-code-string.js
  61. 76 76
      src/components/dialog-wrap/format-dialog-item.js
  62. 11 11
      src/components/dialog-wrap/format-field-download-url.js
  63. 7 7
      src/components/dialog-wrap/generate-client-unique-id.js
  64. 19 19
      src/components/dialog-wrap/temp-image.js
  65. 6 6
      src/components/dialog-wrap/temp-wendangzhineng-docs.js
  66. 31 32
      src/components/file/FileNameDisplay.vue
  67. 8 8
      src/components/footer/index.vue
  68. 28 26
      src/components/image-editor/ImgEditBtn.vue
  69. 9 9
      src/components/image-editor/TuiImageEditorVue2.vue
  70. 182 187
      src/components/image-editor/TuiImageEditorVue3.vue
  71. 23 23
      src/components/image-editor/img-2-base64.js
  72. 242 231
      src/components/pdf-viewer/PDFViewer.vue
  73. 31 28
      src/components/pdf-viewer/PdfReader.vue
  74. 1 1
      src/components/pdf-viewer/pdfjs.js
  75. 39 41
      src/components/picture-upload/BtnImgDelete.vue
  76. 5 6
      src/components/picture-upload/BtnImgDownload.vue
  77. 18 25
      src/components/picture-upload/FileListTable.vue
  78. 30 30
      src/components/use-available-menus.js
  79. 8 8
      src/main.js
  80. 19 19
      src/router/index.js
  81. 3 3
      src/store/index.ts
  82. 2 2
      src/store/modules/xs-huitu-image-upload/index.ts
  83. 91 91
      src/utils/config.js
  84. 103 103
      src/utils/helper.js
  85. 7 7
      src/views/Analysis.vue
  86. 45 45
      src/views/Answer.vue
  87. 27 27
      src/views/Document.vue
  88. 28 28
      src/views/DocumentAnswer.vue
  89. 12 12
      src/views/DocumentCombine.vue
  90. 269 254
      src/views/DocumentDetail.vue
  91. 41 41
      src/views/DocumentInterlocution.vue
  92. 27 27
      src/views/DocumentQuestion.vue
  93. 27 27
      src/views/DocumentQuestion2.vue
  94. 20 14
      src/views/DocumentsmartData.vue
  95. 527 481
      src/views/Home.vue
  96. 206 197
      src/views/Index.vue
  97. 150 155
      src/views/Knowledge.vue
  98. 137 139
      src/views/Login.vue
  99. 33 36
      src/views/PicArticle.vue
  100. 130 131
      src/views/Register.vue

+ 1 - 1
.editorconfig

@@ -3,6 +3,6 @@ root = true
 end_of_line = lf
 charset = utf-8
 indent_style = space
-indent_size = 4
+indent_size = 2
 insert_final_newline = true
 trim_trailing_whitespace = true

+ 6 - 6
.eslintrc.js

@@ -1,8 +1,8 @@
 module.exports = {
-    extends: ["@easyfe/eslint-config-vue3ts"],
-    plugins: ["@syyfe"],
-    rules: {
-        //检验路由命名规则
-        "@syyfe/validate-router": "error"
-    }
+  extends: ["@easyfe/eslint-config-vue3ts"],
+  plugins: ["@syyfe"],
+  rules: {
+    //检验路由命名规则
+    "@syyfe/validate-router": "error"
+  }
 };

+ 3 - 1
.prettierignore

@@ -1 +1,3 @@
-src
+*.min.js
+*.min.css
+*.map

+ 6 - 6
.prettierrc

@@ -1,8 +1,8 @@
 {
-    "tabWidth": 2,
-    "trailingComma": "none",
-    "endOfLine": "auto",
-    "semi": true,
-    "printWidth": 120,
-    "singleQuote": false
+  "tabWidth": 2,
+  "trailingComma": "none",
+  "endOfLine": "auto",
+  "semi": true,
+  "printWidth": 120,
+  "singleQuote": true
 }

+ 34 - 39
.vscode/settings.json

@@ -1,41 +1,36 @@
 {
-    "editor.defaultFormatter": "esbenp.prettier-vscode",
-    "eslint.format.enable": false,
-    "editor.formatOnSave": false,
-    "editor.formatOnPaste": true,
-    "editor.formatOnType": true,
-    "eslint.run": "onSave",
-    "eslint.validate": ["javascript", "javascriptreact", "vue", "typescript", "typescriptreact"],
-    "editor.codeActionsOnSave": {
-        "source.fixAll.eslint": "explicit"
-    },
-    "[json]": {
-        "editor.defaultFormatter": "esbenp.prettier-vscode"
-    },
-    "[jsonc]": {
-        "editor.defaultFormatter": "esbenp.prettier-vscode"
-    },
-    "[typescript]": {
-        "editor.defaultFormatter": "esbenp.prettier-vscode"
-    },
-    "[html]": {
-        "editor.defaultFormatter": "esbenp.prettier-vscode"
-    },
-    "[less]": {
-        "editor.defaultFormatter": "vscode.css-language-features"
-    },
-    "[javascript]": {
-        "editor.defaultFormatter": "vscode.typescript-language-features"
-    },
-    "[vue]": {
-        "editor.defaultFormatter": "Vue.volar"
-    },
-    "lit-i18n-tool": {
-        "localesPaths": "src/locales",
-        "replace1": "{{$t(%v)}}",
-        "replace2": "$t(%v)",
-        "replace3": "i18n.global.t(%v)",
-        "replace4": "%v"
-    },
-    "i18n-ally.localesPaths": ["src/locales"]
+  "eslint.format.enable": false,
+  "editor.formatOnPaste": true,
+  "editor.formatOnType": true,
+  // 重新设定tabsize
+  "editor.tabSize": 2,
+  "eslint.run": "onSave",
+  "eslint.validate": ["javascript", "javascriptreact", "vue", "typescript", "typescriptreact"],
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": "explicit"
+  },
+  "[json]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[jsonc]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[typescript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[html]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[less]": {
+    "editor.defaultFormatter": "vscode.css-language-features"
+  },
+  "[javascript]": {
+    "editor.defaultFormatter": "vscode.typescript-language-features"
+  },
+  "editor.defaultFormatter": "esbenp.prettier-vscode",
+  // #值设置为true时,每次保存的时候自动格式化;
+  "editor.formatOnSave": true,
+  "[vue]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  }
 }

+ 1 - 1
README.md

@@ -38,7 +38,7 @@ $ npm run build
 
 ## 关于配置文件
 
-项目里一共有2个配置文件,如下:
+项目里一共有 2 个配置文件,如下:
 
 - src/ajax/url-external-config.js
 - src/utils/config.js

+ 11 - 11
index.html

@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <html lang="en">
-    <head>
-        <meta charset="UTF-8" />
-        <link rel="icon" href="/logo.svg" />
-        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-        <title>大模型系统</title>
-        <script src="/config.js"></script>
-    </head>
-    <body>
-        <div id="app"></div>
-        <script type="module" src="/src/main.js"></script>
-    </body>
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" href="/logo.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>大模型系统</title>
+    <script src="/config.js"></script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
 </html>

+ 69 - 62
src/App.vue

@@ -1,79 +1,86 @@
 <template>
-    <RouterView />
-    <section v-show="isLoading">
-        <a-spin dot />
-    </section>
-    <a-modal v-model:visible="showMask" :hide-cancel="true" :simple="true" :mask-closable="false" ok-text="重试"
-        :title="maskTitle" @ok="reload">
-    </a-modal>
+  <RouterView />
+  <section v-show="isLoading">
+    <a-spin dot />
+  </section>
+  <a-modal
+    v-model:visible="showMask"
+    :hide-cancel="true"
+    :simple="true"
+    :mask-closable="false"
+    ok-text="重试"
+    :title="maskTitle"
+    @ok="reload"
+  >
+  </a-modal>
 </template>
 <script>
-import { RouterView } from "vue-router";
-import { defineComponent, ref, onMounted, inject, onBeforeUnmount } from "vue";
+import { RouterView } from 'vue-router';
+import { defineComponent, ref, onMounted, inject, onBeforeUnmount } from 'vue';
 export default defineComponent({
-    components: {
-        RouterView
-    },
-    setup() {
-        const isLoading = ref(false);
-        const maskTitle = ref("");
-        const showMask = ref(false);
-        const { helper } = inject("$global");
-        let callbackFunc = () => { };
-        onMounted(() => {
-            helper.$bus.on("set-loading", (value) => {
-                setTimeout(
-                    () => {
-                        isLoading.value = value;
-                    },
-                    value ? 20 : 1000
-                );
-            });
-            helper.$bus.on("set-mask", ({ title, callback }) => {
-                maskTitle.value = title;
-                showMask.value = true;
-                callbackFunc = callback;
-            });
-        });
-        const reload = () => {
-            maskTitle.value = "";
-            showMask.value = false;
-            callbackFunc();
-        };
-        onBeforeUnmount(() => {
-            helper.$bus.off("set-loading");
-            helper.$bus.off("set-mask");
-        });
-        return {
-            reload,
-            isLoading,
-            maskTitle,
-            showMask
-        };
-    }
+  components: {
+    RouterView
+  },
+  setup() {
+    const isLoading = ref(false);
+    const maskTitle = ref('');
+    const showMask = ref(false);
+    const { helper } = inject('$global');
+    let callbackFunc = () => {};
+    onMounted(() => {
+      helper.$bus.on('set-loading', (value) => {
+        setTimeout(
+          () => {
+            isLoading.value = value;
+          },
+          value ? 20 : 1000
+        );
+      });
+      helper.$bus.on('set-mask', ({ title, callback }) => {
+        maskTitle.value = title;
+        showMask.value = true;
+        callbackFunc = callback;
+      });
+    });
+    const reload = () => {
+      maskTitle.value = '';
+      showMask.value = false;
+      callbackFunc();
+    };
+    onBeforeUnmount(() => {
+      helper.$bus.off('set-loading');
+      helper.$bus.off('set-mask');
+    });
+    return {
+      reload,
+      isLoading,
+      maskTitle,
+      showMask
+    };
+  }
 });
 </script>
 <style>
 .arco-modal-simple .arco-modal-header {
-    margin-bottom: 0;
+  margin-bottom: 0;
 }
 
 body {
-    --primary-6: 59, 202, 168;
-    --primary-5: 59 202 168 / 80%;
-    --danger-6: 255, 110, 110;
+  --primary-6: 59, 202, 168;
+  --primary-5: 59 202 168 / 80%;
+  --danger-6: 255, 110, 110;
 }
 </style>
 <style scoped>
 section {
-    position: absolute;
-    left: 0;
-    top: 0;
-    bottom: 0;
-    right: 0;
-    z-index: 100000;
-    display: flex;
-    align-items: center;
-    justify-content: center;
+  position: absolute;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  right: 0;
+  z-index: 100000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 </style>

+ 5 - 5
src/ajax/api/agent.js

@@ -5,8 +5,8 @@ import request from "../request";
  * @returns {Promise<Object>}
  */
 const getAgents = () => {
-    // return request.get("/api/agent/list");
-    return request.get("/api/user/menus");
+  // return request.get("/api/agent/list");
+  return request.get("/api/user/menus");
 };
 
 /**
@@ -14,10 +14,10 @@ const getAgents = () => {
  * @returns {Promise<Object>}
  */
 const getVariables = (id) => {
-    return request.get(`/api/report/variables/list?agent_id=${id}`);
+  return request.get(`/api/report/variables/list?agent_id=${id}`);
 };
 
 export default {
-    getAgents,
-    getVariables
+  getAgents,
+  getVariables
 };

+ 1 - 1
src/ajax/api/document.js

@@ -20,4 +20,4 @@ const getGuideOrBrainMap = (id) => {
 export default {
   getDocument,
   getGuideOrBrainMap
-};
+};

+ 1 - 1
src/ajax/api/knowledge.js

@@ -66,4 +66,4 @@ export default {
   getKnowledge,
   uploadFiles,
   getTask
-};
+};

+ 1 - 1
src/ajax/api/message.js

@@ -1,6 +1,6 @@
 import request from "../request";
 const create = (token, agentId, dialogId, type) => {
-    const socket_url = window.WEBSOCKET_BASE_URL;
+  const socket_url = window.WEBSOCKET_BASE_URL;
 
   const wsParam = type === "report" ? "report" : "chat";
   const wsUrl =

+ 17 - 17
src/ajax/api/user.js

@@ -7,7 +7,7 @@ import { encrypt } from '../../utils/jsencrypt';
  * @returns {Promise<Object>}
  */
 const getInfo = () => {
-    return request.get("/app-api/member/user/get");
+  return request.get("/app-api/member/user/get");
 };
 
 /**
@@ -17,15 +17,15 @@ const getInfo = () => {
  * @returns {Promise<Object>}
  */
 const login = (username, password) => {
-    // const url = "/api/auth/login";
-    const url = "/api/auth/v2/login";
+  // const url = "/api/auth/login";
+  const url = "/api/auth/v2/login";
 
-    const pswd = encrypt(password);
+  const pswd = encrypt(password);
 
-    return request.post(url, {
-        username,
-        password: pswd
-    });
+  return request.post(url, {
+    username,
+    password: pswd
+  });
 };
 
 /**
@@ -35,10 +35,10 @@ const login = (username, password) => {
  * @returns {Promise<Object>}
  */
 const register = (username, password) => {
-    return request.post("/api/auth/register", {
-        username,
-        password
-    });
+  return request.post("/api/auth/register", {
+    username,
+    password
+  });
 };
 
 /**
@@ -46,12 +46,12 @@ const register = (username, password) => {
  * @returns {Promise<Object>}
  */
 const getToken = () => {
-    return request.get("/api/auth/token");
+  return request.get("/api/auth/token");
 };
 
 export default {
-    login,
-    register,
-    getToken,
-    getInfo
+  login,
+  register,
+  getToken,
+  getInfo
 };

+ 7 - 7
src/ajax/document.js

@@ -9,19 +9,19 @@ const server_url = REFFERENCE_ASSETS_FILE_URL;
 /**
  * 获取一个文档的链接
  * 使用位置1:文档引用效果中的pdf文件展示
- * @param {string} doc_id 
- * @returns 
+ * @param {string} doc_id
+ * @returns
  */
 export const getDocumentUrl = (doc_id) => {
-    return `${server_url}/v1/document/get/${doc_id}`;
+  return `${server_url}/v1/document/get/${doc_id}`;
 }
 
 /**
  * 获取一个图片的链接
  * 使用位置1:文档引用效果中,浮层左侧小图片展示
- * @param {string} image_id 
- * @returns 
+ * @param {string} image_id
+ * @returns
  */
 export const getImageUrl = (image_id) => {
-    return `${server_url}/v1/document/image/${image_id}`
-}
+  return `${server_url}/v1/document/image/${image_id}`
+}

+ 6 - 6
src/ajax/index.js

@@ -5,12 +5,12 @@ import document from "./api/document";
 import message from "./api/message";
 import file from "./api/file";
 const api = {
-    user,
-    agent,
-    knowledge,
-    document,
-    message,
-    file
+  user,
+  agent,
+  knowledge,
+  document,
+  message,
+  file
 };
 
 export default api;

+ 11 - 11
src/ajax/replace-proxy-url.js

@@ -1,17 +1,17 @@
 const getConfigField = (key) => {
-    if (!key) {
-        return null;
-    }
+  if (!key) {
+    return null;
+  }
 
-    // if (!config) {
-    //   return null;
-    // }
+  // if (!config) {
+  //   return null;
+  // }
 
-    if (key in window) {
-        return window[key];
-    } else {
-        return null;
-    }
+  if (key in window) {
+    return window[key];
+  } else {
+    return null;
+  }
 };
 
 /**

+ 3 - 16
src/assets/base.css

@@ -62,23 +62,10 @@ body {
   min-height: 100vh;
   color: var(--color-text);
   background: var(--color-background);
-  transition:
-    color 0.5s,
-    background-color 0.5s;
+  transition: color 0.5s, background-color 0.5s;
   line-height: 1.6;
-  font-family:
-    Inter,
-    -apple-system,
-    BlinkMacSystemFont,
-    'Segoe UI',
-    Roboto,
-    Oxygen,
-    Ubuntu,
-    Cantarell,
-    'Fira Sans',
-    'Droid Sans',
-    'Helvetica Neue',
-    sans-serif;
+  font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans',
+    'Droid Sans', 'Helvetica Neue', sans-serif;
   font-size: 15px;
   text-rendering: optimizeLegibility;
   -webkit-font-smoothing: antialiased;

+ 5 - 5
src/assets/main.css

@@ -1,7 +1,7 @@
-@import "./base.css";
+@import './base.css';
 #app {
-    display: flex;
-    width: 100vw;
-    height: 100vh;
-    background: #f6f8ff;
+  display: flex;
+  width: 100vw;
+  height: 100vh;
+  background: #f6f8ff;
 }

+ 90 - 90
src/components/DialogFeedback.vue

@@ -1,102 +1,102 @@
 <template>
-    <a-modal v-model:visible="showFeedback" @beforeOk="handleOk" @beforeCancel="handleCancel" okText="提交">
-        <template #title> 进一步反馈 </template>
-        <p class="feedback-title">理解问题有误</p>
-        <a-checkbox-group v-model="feedbackValue1" class="feedback-content">
-            <a-grid :cols="2" :colGap="10" :rowGap="8">
-                <a-grid-item>
-                    <a-checkbox value="1">没能理解指令</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="2">未发现问题中的错误</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="3">无法理解上下文</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="4">答非所问</a-checkbox>
-                </a-grid-item>
-            </a-grid>
-        </a-checkbox-group>
-        <p class="feedback-title">回答不佳</p>
-        <a-checkbox-group v-model="feedbackValue2" class="feedback-content">
-            <a-grid :cols="2" :colGap="10" :rowGap="8">
-                <a-grid-item>
-                    <a-checkbox value="1">有事实性错误</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="2">回答重复</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="3">格式错误</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="4">对我没帮助</a-checkbox>
-                </a-grid-item>
-            </a-grid>
-        </a-checkbox-group>
-        <p class="feedback-title">有害信息</p>
-        <a-checkbox-group v-model="feedbackValue3" class="feedback-content">
-            <a-grid :cols="2" :colGap="10" :rowGap="8">
-                <a-grid-item>
-                    <a-checkbox value="1">敏感/有害回复</a-checkbox>
-                </a-grid-item>
-                <a-grid-item>
-                    <a-checkbox value="2">存在价值观问题</a-checkbox>
-                </a-grid-item>
-            </a-grid>
-        </a-checkbox-group>
-        <p class="feedback-title">你认为更理想的答复是什么?</p>
-        <a-textarea
-            v-model="feedbackValue4"
-            :style="{
-                width: '100%',
-                height: '100px',
-                border: '1px solid rgba(187, 187, 187, 1)',
-                background: 'rgba(0,0,0,0)'
-            }"
-            auto-size
-            placeholder="请输入"
-            allow-clear
-        />
-    </a-modal>
+  <a-modal v-model:visible="showFeedback" @beforeOk="handleOk" @beforeCancel="handleCancel" okText="提交">
+    <template #title> 进一步反馈 </template>
+    <p class="feedback-title">理解问题有误</p>
+    <a-checkbox-group v-model="feedbackValue1" class="feedback-content">
+      <a-grid :cols="2" :colGap="10" :rowGap="8">
+        <a-grid-item>
+          <a-checkbox value="1">没能理解指令</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="2">未发现问题中的错误</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="3">无法理解上下文</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="4">答非所问</a-checkbox>
+        </a-grid-item>
+      </a-grid>
+    </a-checkbox-group>
+    <p class="feedback-title">回答不佳</p>
+    <a-checkbox-group v-model="feedbackValue2" class="feedback-content">
+      <a-grid :cols="2" :colGap="10" :rowGap="8">
+        <a-grid-item>
+          <a-checkbox value="1">有事实性错误</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="2">回答重复</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="3">格式错误</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="4">对我没帮助</a-checkbox>
+        </a-grid-item>
+      </a-grid>
+    </a-checkbox-group>
+    <p class="feedback-title">有害信息</p>
+    <a-checkbox-group v-model="feedbackValue3" class="feedback-content">
+      <a-grid :cols="2" :colGap="10" :rowGap="8">
+        <a-grid-item>
+          <a-checkbox value="1">敏感/有害回复</a-checkbox>
+        </a-grid-item>
+        <a-grid-item>
+          <a-checkbox value="2">存在价值观问题</a-checkbox>
+        </a-grid-item>
+      </a-grid>
+    </a-checkbox-group>
+    <p class="feedback-title">你认为更理想的答复是什么?</p>
+    <a-textarea
+      v-model="feedbackValue4"
+      :style="{
+        width: '100%',
+        height: '100px',
+        border: '1px solid rgba(187, 187, 187, 1)',
+        background: 'rgba(0,0,0,0)'
+      }"
+      auto-size
+      placeholder="请输入"
+      allow-clear
+    />
+  </a-modal>
 </template>
 <script>
-import { defineComponent, ref } from "vue";
+import { defineComponent, ref } from 'vue';
 export default defineComponent({
-    components: {},
-    props: ["showFeedback"],
-    setup(props, { emit }) {
-        const feedbackValue1 = ref([]);
-        const feedbackValue2 = ref([]);
-        const feedbackValue3 = ref([]);
-        const feedbackValue4 = ref("");
-        const handleOk = () => {
-            emit("handle-ok");
-            return false;
-        };
-        const handleCancel = () => {
-            emit("handle-cancel");
-            return false;
-        };
-        return {
-            feedbackValue1,
-            feedbackValue2,
-            feedbackValue3,
-            feedbackValue4,
-            handleOk,
-            handleCancel
-        };
-    }
+  components: {},
+  props: ['showFeedback'],
+  setup(props, { emit }) {
+    const feedbackValue1 = ref([]);
+    const feedbackValue2 = ref([]);
+    const feedbackValue3 = ref([]);
+    const feedbackValue4 = ref('');
+    const handleOk = () => {
+      emit('handle-ok');
+      return false;
+    };
+    const handleCancel = () => {
+      emit('handle-cancel');
+      return false;
+    };
+    return {
+      feedbackValue1,
+      feedbackValue2,
+      feedbackValue3,
+      feedbackValue4,
+      handleOk,
+      handleCancel
+    };
+  }
 });
 </script>
 <style scoped>
 .feedback-title {
-    color: rgba(102, 102, 102, 1);
-    font-size: 12px;
-    margin: 0 0 8px 4px;
+  color: rgba(102, 102, 102, 1);
+  font-size: 12px;
+  margin: 0 0 8px 4px;
 }
 .feedback-content {
-    margin-bottom: 16px;
+  margin-bottom: 16px;
 }
 </style>

ファイルの差分が大きいため隠しています
+ 908 - 906
src/components/DialogWrap.vue


+ 135 - 122
src/components/Directory.vue

@@ -1,43 +1,56 @@
 <template>
-<div class="knowledge-name">
-  <span></span>
-  <a-typography-paragraph style="flex: 1; margin: 0 0 0 8px; font-size: 14px; color: rgba(16, 16, 16, 1);" :ellipsis="{rows: 1, css: true}">{{knowledgeInfo.name}}</a-typography-paragraph>
-</div>
-<a-upload
-  :multiple="false"
-  :show-file-list="false"
-  :limit="1"
-  :show-upload-button="{showOnExceedLimit: true}"
-  accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx"
-  style="display: block; width: 100%;"
->
-  <template #upload-button>
-    <div class="upload-main">
-      <div>
-        <img src="@/assets/icons/iconPark-inbox-out.svg" width="12" />
-        <p>添加文件</p>
+  <div class="knowledge-name">
+    <span></span>
+    <a-typography-paragraph
+      style="flex: 1; margin: 0 0 0 8px; font-size: 14px; color: rgba(16, 16, 16, 1)"
+      :ellipsis="{ rows: 1, css: true }"
+      >{{ knowledgeInfo.name }}</a-typography-paragraph
+    >
+  </div>
+  <a-upload
+    :multiple="false"
+    :show-file-list="false"
+    :limit="1"
+    :show-upload-button="{ showOnExceedLimit: true }"
+    accept=".pdf,.doc,.docx,.txt,.md,.ppt.pptx"
+    style="display: block; width: 100%"
+  >
+    <template #upload-button>
+      <div class="upload-main">
+        <div>
+          <img src="@/assets/icons/iconPark-inbox-out.svg" width="12" />
+          <p>添加文件</p>
+        </div>
       </div>
+    </template>
+  </a-upload>
+  <p class="knowledge-length">14个文件</p>
+  <div class="knowledge-list">
+    <div
+      v-for="(item, key) in list"
+      :key="key"
+      :class="[item.status === '5' ? (item.id === documentId ? 'active' : 'method') : '']"
+      @click="goDocument(item)"
+    >
+      <img src="@/assets/icons/iconPark-notes.svg" width="10" />
+      <div :class="[item.status !== 2 ? 'opacity' : '']">
+        <a-typography-paragraph
+          style="flex: 1; margin: 0 0 0 8px; font-size: 14px; color: rgba(16, 16, 16, 1)"
+          :ellipsis="{ rows: 1, css: true }"
+          >{{ item.fileName }}</a-typography-paragraph
+        >
+      </div>
+      <section v-if="item.status === 4 || item.status === 5">
+        <p>{{ item.status === 4 ? '上传中' : '解析中' }}...</p>
+        <img src="@/assets/icons/riLine-loader-4-line.svg" width="12" class="rotate" />
+      </section>
+      <section v-if="item.status === 1 || ![1, 2, 4, 5].includes(item.status)">
+        <p>{{ item.status === 1 ? '上传' : '解析' }}失败</p>
+        <img src="@/assets/icons/riLine-delete-bin-4-line.svg" width="12" class="method" />
+        <img src="@/assets/icons/riLine-repeat-2-line.svg" width="12" class="method" />
+      </section>
     </div>
-  </template>
-</a-upload>
-<p class="knowledge-length">14个文件</p>
-<div class="knowledge-list">
-  <div v-for="(item, key) in list" :key="key" :class="[item.status === '5' ? (item.id === documentId ? 'active' : 'method') : '']" @click="goDocument(item)">
-    <img src="@/assets/icons/iconPark-notes.svg" width="10" />
-    <div :class="[item.status !== 2 ? 'opacity' : '']">
-      <a-typography-paragraph style="flex: 1; margin: 0 0 0 8px; font-size: 14px; color: rgba(16, 16, 16, 1);" :ellipsis="{rows: 1, css: true}">{{item.fileName}}</a-typography-paragraph>
-    </div>
-    <section v-if="item.status === 4 || item.status === 5">
-      <p>{{item.status === 4 ? '上传中' : '解析中'}}...</p>
-      <img src="@/assets/icons/riLine-loader-4-line.svg" width="12" class="rotate" />
-    </section>
-    <section v-if="item.status === 1 || ![1,2,4,5].includes(item.status)">
-      <p>{{item.status === 1 ? '上传' : '解析'}}失败</p>
-      <img src="@/assets/icons/riLine-delete-bin-4-line.svg" width="12" class="method" />
-      <img src="@/assets/icons/riLine-repeat-2-line.svg" width="12" class="method" />
-    </section>
   </div>
-</div>
 </template>
 <script>
 import { useRoute } from 'vue-router';
@@ -55,13 +68,13 @@ export default defineComponent({
     const goDocument = (item) => {
       const { status, id } = item;
       // if (status === 2) {
-        helper.goLink('document', { documentId: id, knowledgeId: route.query.knowledgeId });
+      helper.goLink('document', { documentId: id, knowledgeId: route.query.knowledgeId });
       // };
     };
     watch(
       () => route.query,
       (query) => {
-       documentId.value = query.documentId;
+        documentId.value = query.documentId;
       }
     );
     const init = async () => {
@@ -87,7 +100,7 @@ export default defineComponent({
       documentId
     };
   }
-})
+});
 </script>
 <style>
 .arco-upload {
@@ -95,104 +108,104 @@ export default defineComponent({
 }
 </style>
 <style scoped>
-  .knowledge-name {
-    margin: 16px 0 12px 0;
-    height: 20px;
+.knowledge-name {
+  margin: 16px 0 12px 0;
+  height: 20px;
+  display: flex;
+  align-items: center;
+  > span {
+    display: block;
+    width: 10px;
+    height: 10px;
+    border-radius: 5px;
+    background-color: rgba(97, 210, 112, 1);
+  }
+}
+.upload-main {
+  width: 100%;
+  height: 36px;
+  border-radius: 6px;
+  background-color: rgba(136, 176, 75, 1);
+  color: rgba(255, 255, 255, 1);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  &:hover {
+    background-color: rgba(136, 176, 75, 0.8);
+  }
+  > div {
     display: flex;
-    align-items: center;
-    >span {
-      display: block;
-      width: 10px;
-      height: 10px;
-      border-radius: 5px;
-      background-color: rgba(97, 210, 112, 1);
+    > p {
+      font-weight: bold;
+      margin-left: 4px;
     }
   }
-  .upload-main {
-    width: 100%;
-    height: 36px;
-    border-radius: 6px;
-    background-color: rgba(136, 176, 75, 1);
-    color: rgba(255, 255, 255, 1);
+}
+.knowledge-length {
+  color: rgba(153, 153, 153, 1);
+  font-size: 12px;
+  margin: 12px 0;
+}
+.knowledge-list {
+  flex: 1;
+  overflow-y: auto;
+  > div {
+    height: 28px;
+    margin-top: 8px;
     display: flex;
     align-items: center;
-    justify-content: center;
-    &:hover {
-      background-color: rgba(136, 176, 75, .8);
+    position: relative;
+    padding-left: 4px;
+    border-radius: 4px;
+    &.active {
+      background: #fff;
     }
-    >div {
-      display: flex;
-      >p {
-        font-weight: bold;
-        margin-left: 4px;
+    &.method {
+      cursor: pointer;
+      &:hover {
+        background: rgba(236, 236, 236, 1);
       }
     }
-  }
-  .knowledge-length {
-    color: rgba(153, 153, 153, 1);
-    font-size: 12px;
-    margin: 12px 0;
-  }
-  .knowledge-list {
-    flex: 1;
-    overflow-y: auto;
-    >div {
+    > div {
+      &.opacity {
+        width: 60%;
+        mask: linear-gradient(90deg, #fff, transparent);
+      }
+    }
+    > section {
+      position: absolute;
+      right: 0;
+      top: 0;
       height: 28px;
-      margin-top: 8px;
       display: flex;
       align-items: center;
-      position: relative;
-      padding-left: 4px;
-      border-radius: 4px;
-      &.active {
-        background: #fff;
-      }
-      &.method {
-        cursor: pointer;
-        &:hover {
-          background: rgba(236, 236, 236, 1);
-        }
-      }
-      >div {
-        &.opacity {
-          width: 60%;
-          mask: linear-gradient(90deg, #fff, transparent);
+      z-index: 2;
+      > img {
+        margin-left: 6px;
+        &.rotate {
+          animation: rotate 2s linear infinite;
         }
-      }
-      >section {
-        position: absolute;
-        right: 0;
-        top: 0;
-        height: 28px;
-        display: flex;
-        align-items: center;
-        z-index: 2;
-        >img {
-          margin-left: 6px;
-          &.rotate {
-            animation: rotate 2s linear infinite;
+        &.method {
+          cursor: pointer;
+          &:hover {
+            opacity: 0.8;
           }
-          &.method {
-            cursor: pointer;
-            &:hover {
-              opacity: .8;
-            }
-          }
-        }
-        >p {
-          font-weight: bold;
-          color: rgba(148, 155, 137, 1);
-          font-size: 12px;
         }
       }
+      > p {
+        font-weight: bold;
+        color: rgba(148, 155, 137, 1);
+        font-size: 12px;
+      }
     }
   }
-  @keyframes rotate {
-    from {
-      transform: rotate(0deg);
-    }
-    to {
-      transform: rotate(360deg);
-    }
+}
+@keyframes rotate {
+  from {
+    transform: rotate(0deg);
   }
-</style>
+  to {
+    transform: rotate(360deg);
+  }
+}
+</style>

+ 146 - 126
src/components/DocumentCards.vue

@@ -10,15 +10,23 @@
       </div>
     </section>
     <footer v-if="hasUpload" class="excel-upload-container">
-      <a-popover :popup-visible="showUpload" position="tl" @popup-visible-change="() => {
-        showDeleteTooltip = false;
-      }
-        ">
-        <div :class="{ 'text-hide': showUpload }">
-          <div @click="() => {
-            showUpload = true;
+      <a-popover
+        :popup-visible="showUpload"
+        position="tl"
+        @popup-visible-change="
+          () => {
+            showDeleteTooltip = false;
           }
-            ">
+        "
+      >
+        <div :class="{ 'text-hide': showUpload }">
+          <div
+            @click="
+              () => {
+                showUpload = true;
+              }
+            "
+          >
             <img src="@/assets/document/3.svg" class="img-normal" v-if="!showUpload" />
             <img src="@/assets/document/4.svg" class="img-hover" v-if="!showUpload" />
             <img src="@/assets/document/5.svg" class="img-active" v-if="showUpload" />
@@ -28,54 +36,57 @@
         <template #content>
           <div :class="{ 'upload-wrap': true, 'upload-wrap-narrow': uploadFile }">
             <header>
-              <p>{{ uploadFile ? "上传文档" : "文档解析站" }}</p>
-              <div @click="() => {
-                showUpload = false;
-              }
-                ">
+              <p>{{ uploadFile ? '上传文档' : '文档解析站' }}</p>
+              <div
+                @click="
+                  () => {
+                    showUpload = false;
+                  }
+                "
+              >
                 <icon-close size="large" />
               </div>
             </header>
             <div>
               <section v-if="agengtName == '智能数据'">
-                <a-upload draggable
-                          :multiple="true"
-                          :limit="50"
-                          :show-file-list="false"
-                          @before-upload="onBeforeUpload"
-                          @exceed-limit="onExceedLimit"
-                          @before-remove="onBeforeRemove"
-                          :custom-request="customRequest"
-                          :show-upload-button="{ showOnExceedLimit: true }"
-                          accept=".xls,.xlsx,.csv,.db">
+                <a-upload
+                  draggable
+                  :multiple="true"
+                  :limit="50"
+                  :show-file-list="false"
+                  @before-upload="onBeforeUpload"
+                  @exceed-limit="onExceedLimit"
+                  @before-remove="onBeforeRemove"
+                  :custom-request="customRequest"
+                  :show-upload-button="{ showOnExceedLimit: true }"
+                  accept=".xls,.xlsx,.csv,.db"
+                >
                   <template #upload-button>
                     <div class="upload-main">
                       <p>拖拽文档到这里,或<span>点此上传</span></p>
-                      <span>
-                        支持上传 Excel (.xls, .xlsx),CSV (.csv),DB (.db),大小不超过30M
-                      </span>
+                      <span> 支持上传 Excel (.xls, .xlsx),CSV (.csv),DB (.db),大小不超过30M </span>
                     </div>
                   </template>
                 </a-upload>
               </section>
 
               <section v-else>
-                <a-upload draggable
-                          :multiple="!uploadFile"
-                          :limit="50"
-                          :show-file-list="false"
-                          @before-upload="onBeforeUpload"
-                          @exceed-limit="onExceedLimit"
-                          @before-remove="onBeforeRemove"
-                          :custom-request="customRequest"
-                          :show-upload-button="{ showOnExceedLimit: true }"
-                          accept=".txt,.pdf,.xlsx">
+                <a-upload
+                  draggable
+                  :multiple="!uploadFile"
+                  :limit="50"
+                  :show-file-list="false"
+                  @before-upload="onBeforeUpload"
+                  @exceed-limit="onExceedLimit"
+                  @before-remove="onBeforeRemove"
+                  :custom-request="customRequest"
+                  :show-upload-button="{ showOnExceedLimit: true }"
+                  accept=".txt,.pdf,.xlsx"
+                >
                   <template #upload-button>
                     <div class="upload-main">
                       <p>拖拽文档到这里,或<span>点此上传</span></p>
-                      <span>
-                        支持上传{{ uploadFile ? ".txt,.pdf" : ".xlsx‌文档" }},大小不超过30M
-                      </span>
+                      <span> 支持上传{{ uploadFile ? '.txt,.pdf' : '.xlsx‌文档' }},大小不超过30M </span>
                     </div>
                   </template>
                 </a-upload>
@@ -86,8 +97,14 @@
                   <span>共{{ tableData.length }}个</span>
                 </p>
                 <div>
-                  <a-table :pagination="false" row-key="name" :columns="columns" :data="tableData"
-                    :row-selection="rowSelection" v-model:selectedKeys="selectedKeys">
+                  <a-table
+                    :pagination="false"
+                    row-key="name"
+                    :columns="columns"
+                    :data="tableData"
+                    :row-selection="rowSelection"
+                    v-model:selectedKeys="selectedKeys"
+                  >
                     <template #methods="{ record }">
                       <!-- <a-tooltip content="下载">
                         <div class="method-button" @click="downloadDocument(record)">
@@ -105,12 +122,19 @@
                             <p>删除后无法恢复,您是否删除?</p>
                             <div class="delete-buttons">
                               <div>
-                                <a-button size="mini" type="primary" style="margin-right: 10px"
-                                  @click="deleteDocument">确认</a-button>
-                                <a-button size="mini" type="outline" @click="() => {
-                                  showDeleteTooltip = false;
-                                }
-                                  ">取消</a-button>
+                                <a-button size="mini" type="primary" style="margin-right: 10px" @click="deleteDocument"
+                                  >确认</a-button
+                                >
+                                <a-button
+                                  size="mini"
+                                  type="outline"
+                                  @click="
+                                    () => {
+                                      showDeleteTooltip = false;
+                                    }
+                                  "
+                                  >取消</a-button
+                                >
                               </div>
                             </div>
                           </div>
@@ -125,11 +149,9 @@
           <div class="bottom-buttons">
             <div>
               <a-button type="outline" style="margin-right: 10px" @click="selectFiles(false)">取消</a-button>
-              <a-button :loading="buttonLoading" type="primary" @click="selectFiles(true, 'paper')">去{{
-                uploadFile ? '提问'
-                  : '合并'
-              }}({{ tableData.length
-                }})</a-button>
+              <a-button :loading="buttonLoading" type="primary" @click="selectFiles(true, 'paper')"
+                >去{{ uploadFile ? '提问' : '合并' }}({{ tableData.length }})</a-button
+              >
             </div>
           </div>
         </template>
@@ -138,13 +160,13 @@
   </main>
 </template>
 <script>
-import dayjs from "dayjs";
-import { defineComponent, ref, inject, reactive } from "vue";
+import dayjs from 'dayjs';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-  props: ["data", "hasUpload", "uploadFile", "isQuestion", "agentId", "agengtName"],
+  props: ['data', 'hasUpload', 'uploadFile', 'isQuestion', 'agentId', 'agengtName'],
   setup(props) {
     const showUpload = ref(false);
-    const { helper, ajax } = inject("$global");
+    const { helper, ajax } = inject('$global');
 
     const maxSize = 30 * 1024 * 1024;
     let fileList = ref([]);
@@ -152,14 +174,14 @@ export default defineComponent({
     let formData = new FormData();
     let inputData = ref([]);
     const showDeleteTooltip = ref(false);
-    const deleteId = ref("");
+    const deleteId = ref('');
     const buttonLoading = ref(false);
     const selectFiles = async (isSelect, type) => {
       if (isSelect) {
         if (props.uploadFile) {
           const data = await ajax.message.createDialog(props.agentId);
-          fileList.value.forEach(file => {
-            formData.append('file', file)
+          fileList.value.forEach((file) => {
+            formData.append('file', file);
           });
           buttonLoading.value = true;
           const result = await ajax.file.uploadFile(props.agentId, data.chat_id, formData);
@@ -180,34 +202,32 @@ export default defineComponent({
           inputData.value.push({
             name: result.file_name,
             file_path: result.file_path,
-            value: ""
+            value: ''
           });
 
           const sendData = {
             chatHistory: [],
             chat_id: data.chat_id,
             agent_id: props.agentId,
-            name: "文档智能",
-            description: "文档智能",
+            name: '文档智能',
+            description: '文档智能',
             inputs: {
-              report_name: inputData.value.map(item => item.name).join(', '),
-              id: "Report-PRcYL",
+              report_name: inputData.value.map((item) => item.name).join(', '),
+              id: 'Report-PRcYL',
               data: inputData.value
             }
           };
           if (sendData) {
             helper.write('sendData', sendData);
           }
-
         } else {
-          fileList.value.forEach(file => {
-            formData.append('files', file)
+          fileList.value.forEach((file) => {
+            formData.append('files', file);
           });
           await ajax.file.uploadExcels(formData);
-          helper.$bus.emit("open-dialog", '合并Excel');
+          helper.$bus.emit('open-dialog', '合并Excel');
         }
       }
-
     };
     const handleDeleteButton = (id) => {
       showDeleteTooltip.value = true;
@@ -215,35 +235,35 @@ export default defineComponent({
     };
     const onBeforeUpload = (file) => {
       if (file.size > maxSize) {
-        helper.message("error", `上传文件大小不能超过10M`);
+        helper.message('error', `上传文件大小不能超过10M`);
         return false;
       }
       const fileName = file.name;
-      const existingFile = tableData.find(item => item.name === fileName);
+      const existingFile = tableData.find((item) => item.name === fileName);
       if (existingFile) {
-          helper.message("error", `文件 "${fileName}" 已经上传过`);
-          return false;
+        helper.message('error', `文件 "${fileName}" 已经上传过`);
+        return false;
       }
       return true;
     };
     const onExceedLimit = () => {
-      helper.message("error", `最多上传50个文件`);
+      helper.message('error', `最多上传50个文件`);
     };
     const customRequest = async (option) => {
       const { onSuccess, fileItem } = option;
       const { file } = fileItem;
-      const existingFile = tableData.find(item => item.name === file.name);
-        if (!existingFile) {
-            tableData.push({
-                key: `uid-${Date.now()}-${Math.floor(Math.random() * 1000)}`,
-                name: file.name,
-                type: file.type,
-                size: helper.formatSize(file.size),
-                time: dayjs(file.lastModified).format("YYYY-MM-DD HH:mm:ss")
-            });
-            fileList.value.push(file);
-        }
-        onSuccess();
+      const existingFile = tableData.find((item) => item.name === file.name);
+      if (!existingFile) {
+        tableData.push({
+          key: `uid-${Date.now()}-${Math.floor(Math.random() * 1000)}`,
+          name: file.name,
+          type: file.type,
+          size: helper.formatSize(file.size),
+          time: dayjs(file.lastModified).format('YYYY-MM-DD HH:mm:ss')
+        });
+        fileList.value.push(file);
+      }
+      onSuccess();
     };
     const onBeforeRemove = (data) => {
       fileList.value = fileList.value.filter((item) => item.id !== data.uid);
@@ -252,48 +272,48 @@ export default defineComponent({
     const selectedKeys = ref([]);
 
     const rowSelection = reactive({
-      type: "checkbox",
+      type: 'checkbox',
       showCheckedAll: true,
       onlyCurrent: false
     });
 
     const columns = [
       {
-        title: "文件名称",
-        dataIndex: "name",
+        title: '文件名称',
+        dataIndex: 'name',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "类型",
-        dataIndex: "type",
+        title: '类型',
+        dataIndex: 'type',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "大小",
-        dataIndex: "size"
+        title: '大小',
+        dataIndex: 'size'
       },
       {
-        title: "上传时间",
-        dataIndex: "time",
+        title: '上传时间',
+        dataIndex: 'time',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "操作",
-        slotName: "methods"
+        title: '操作',
+        slotName: 'methods'
       }
     ];
-    const downloadDocument = (record) => { };
+    const downloadDocument = (record) => {};
     const deleteDocument = () => {
-      const index = tableData.findIndex(item => item.key === deleteId.value);
-      console.log('tableData', tableData)
+      const index = tableData.findIndex((item) => item.key === deleteId.value);
+      console.log('tableData', tableData);
       tableData.splice(index, 1);
-      fileList.value = fileList.value.filter(item => item.uid !== deleteId.value);
+      fileList.value = fileList.value.filter((item) => item.uid !== deleteId.value);
     };
     return {
       agengtName: props.agengtName,
@@ -320,7 +340,7 @@ export default defineComponent({
 });
 </script>
 <style lang="scss" scoped>
-.excel-upload-container{
+.excel-upload-container {
   margin-bottom: 20px;
 }
 
@@ -328,7 +348,7 @@ export default defineComponent({
   display: flex;
   justify-content: right;
 
-  >div {
+  > div {
     display: flex;
   }
 }
@@ -353,24 +373,24 @@ export default defineComponent({
 .upload-main {
   width: 800px;
   height: 109px;
-  background: url("@/assets/document/upload.svg");
+  background: url('@/assets/document/upload.svg');
   margin: 0 auto;
   padding: 24px 0px 24px 277px;
   background-size: 100%;
 
-  >p {
+  > p {
     color: #000;
     font-weight: bold;
     margin-bottom: 5px;
     margin-top: 10px;
 
-    >span {
+    > span {
       color: #00aea3;
       text-decoration: underline;
     }
   }
 
-  >span {
+  > span {
     font-size: 13px;
     color: #7f7f7f;
   }
@@ -382,7 +402,7 @@ main {
   flex-direction: column;
   overflow: hidden;
 
-  >section {
+  > section {
     overflow-y: auto;
     display: flex;
     flex-wrap: wrap;
@@ -392,24 +412,24 @@ main {
       flex: 1;
     }
 
-    >div {
+    > div {
       width: 382px;
       height: 120px;
       padding: 20px 24px;
       border-radius: 8px;
       display: flex;
 
-      >img {
+      > img {
         width: 38px;
         height: 38px;
         margin-right: 12px;
       }
 
-      >div {
+      > div {
         font-size: 18px;
         font-weight: bold;
 
-        >span {
+        > span {
           font-size: 15px;
           font-weight: 400;
           color: #797d7f;
@@ -425,13 +445,13 @@ main {
     }
   }
 
-  >footer {
+  > footer {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-top: auto;
 
-    >div {
+    > div {
       display: inline-flex;
       align-items: center;
       gap: 8px;
@@ -452,17 +472,17 @@ main {
         width: 100px;
         overflow: hidden;
 
-        >div>img {
+        > div > img {
           width: 100px;
         }
       }
 
-      >p {
+      > p {
         overflow: hidden;
         white-space: nowrap;
       }
 
-      >div {
+      > div {
         cursor: pointer;
         width: 110px;
         height: 32px;
@@ -485,21 +505,21 @@ main {
           }
         }
 
-        >img {
+        > img {
           width: 110px;
           height: 32px;
         }
       }
     }
 
-    >section {
+    > section {
       display: flex;
       align-items: center;
       background: rgba(150, 171, 185, 0.2);
       border-radius: 20px;
       padding: 5px 10px;
 
-      >p {
+      > p {
         margin-right: 5px;
       }
     }
@@ -517,18 +537,18 @@ main {
     height: auto;
   }
 
-  >header {
+  > header {
     display: flex;
     align-items: center;
     justify-content: space-between;
     margin-bottom: 13px;
 
-    >p {
+    > p {
       font-size: 18px;
       font-weight: bold;
     }
 
-    >div {
+    > div {
       width: 38px;
       height: 38px;
       border-radius: 6px;
@@ -543,12 +563,12 @@ main {
     }
   }
 
-  >div {
+  > div {
     flex: 1;
     overflow-y: auto;
 
-    >div {
-      >p {
+    > div {
+      > p {
         margin: 20px 0;
         color: #7f7f7f;
         font-size: 13px;

+ 183 - 180
src/components/DocumentReportFooter.vue

@@ -1,83 +1,90 @@
 <template>
-    <footer class="upload-footer wendangbaogaoshengcheng-footer" v-if="start_status !== 3">
-        <a-space size="large">
-            <a-tooltip :content="radio_qingxi_text">
-                <a-radio :value="1" :model-value="act_type" @click="handleRadioClick(1)">文档清洗</a-radio>
-            </a-tooltip>
-
-            <a-tooltip :content="radio_shengcheng_text">
-                <a-radio :value="2" :model-value="act_type" @click="handleRadioClick(2)">报告生成</a-radio>
-            </a-tooltip>
-        </a-space>
-
-        <div class="vertical-placeholder"></div>
-
-        <a-typography-text>
-            标题<span class="attention-requred">*</span>
-        </a-typography-text>
-        <a-input :style="{ flex: '1' }" v-model="textValue" :placeholder="`请输入标题`" allow-clear
-            @input="handleInputChange" />
-
-        <div class="vertical-placeholder"></div>
-
-        <a-typography-text>
-            请上传文件<span class="attention-requred">*</span>
-        </a-typography-text>
-
-
-        <a-upload :file-list="file_list" :multiple="true" :limit="MAX_ACCEPT_FILE" :auto-upload="false"
-            :show-upload-button="{ showOnExceedLimit: false }" accept=".pdf,.docx" @change="handleFileChange">
-            <template #upload-button>
-                <a-tooltip :content="upload_warning_text">
-                    <a-button class="upload-button">
-                        <template #icon>
-                            <icon-upload />
-                        </template>
-
-                        <template #default>点击上传</template>
-                    </a-button>
-                </a-tooltip>
+  <footer class="upload-footer wendangbaogaoshengcheng-footer" v-if="start_status !== 3">
+    <a-space size="large">
+      <a-tooltip :content="radio_qingxi_text">
+        <a-radio :value="1" :model-value="act_type" @click="handleRadioClick(1)">文档清洗</a-radio>
+      </a-tooltip>
+
+      <a-tooltip :content="radio_shengcheng_text">
+        <a-radio :value="2" :model-value="act_type" @click="handleRadioClick(2)">报告生成</a-radio>
+      </a-tooltip>
+    </a-space>
+
+    <div class="vertical-placeholder"></div>
+
+    <a-typography-text> 标题<span class="attention-requred">*</span> </a-typography-text>
+    <a-input
+      :style="{ flex: '1' }"
+      v-model="textValue"
+      :placeholder="`请输入标题`"
+      allow-clear
+      @input="handleInputChange"
+    />
+
+    <div class="vertical-placeholder"></div>
+
+    <a-typography-text> 请上传文件<span class="attention-requred">*</span> </a-typography-text>
+
+    <a-upload
+      :file-list="file_list"
+      :multiple="true"
+      :limit="MAX_ACCEPT_FILE"
+      :auto-upload="false"
+      :show-upload-button="{ showOnExceedLimit: false }"
+      accept=".pdf,.docx"
+      @change="handleFileChange"
+    >
+      <template #upload-button>
+        <a-tooltip :content="upload_warning_text">
+          <a-button class="upload-button">
+            <template #icon>
+              <icon-upload />
             </template>
 
-            <template #file-name="{ fileItem }">
-                <a-tooltip :content="fileItem.name">
-                    <span>{{fileItem.name}}</span>
-                </a-tooltip>
-            </template>
+            <template #default>点击上传</template>
+          </a-button>
+        </a-tooltip>
+      </template>
+
+      <template #file-name="{ fileItem }">
+        <a-tooltip :content="fileItem.name">
+          <span>{{ fileItem.name }}</span>
+        </a-tooltip>
+      </template>
 
-            <!-- <template #upload-item="{ fileItem, index }">
+      <!-- <template #upload-item="{ fileItem, index }">
                 <div>
                     <div>{{ fileItem.name }}</div>
                 </div>
             </template> -->
-        </a-upload>
+    </a-upload>
 
+    <div class="vertical-placeholder"></div>
 
-        <div class="vertical-placeholder"></div>
-
-        <a-button :style="{ width: '500px' }" type="primary" @click="handleStart"
-            :disabled="start_status !== 1">开始</a-button>
-    </footer>
+    <a-button :style="{ width: '500px' }" type="primary" @click="handleStart" :disabled="start_status !== 1"
+      >开始</a-button
+    >
+  </footer>
 </template>
 <script setup>
-import { ref, inject, computed } from "vue";
+import { ref, inject, computed } from 'vue';
 import { Message } from '@arco-design/web-vue';
 
 const props = defineProps({
-    agentId: String,
+  agentId: String
 });
 
-const { config, helper, ajax } = inject("$global");
+const { config, helper, ajax } = inject('$global');
 
 // 操作类型
 const act_type = ref(1);
 const act_opts = [
-    { label: '文档清洗', value: 1 },
-    { label: '报告生成', value: 2 },
+  { label: '文档清洗', value: 1 },
+  { label: '报告生成', value: 2 }
 ];
 
 // 标题
-const textValue = ref("");
+const textValue = ref('');
 const maxLength = ref(120); // 允许输入的最大长度
 
 /**
@@ -86,7 +93,7 @@ const maxLength = ref(120); // 允许输入的最大长度
 const file_list = ref([]);
 const MAX_ACCEPT_FILE = 30;
 const file_total = computed(() => {
-    return file_list.value.length;
+  return file_list.value.length;
 });
 
 /**
@@ -96,45 +103,43 @@ const start_status = ref(1); // 状态值:1 初始 2 进行中 3 成功 4 出
 const start_message = ref('');
 
 const handleRadioClick = (value) => {
-    act_type.value = value / 1;
-}
+  act_type.value = value / 1;
+};
 
 /**
  * 标题数据变化
  * @param value
  */
-const handleInputChange = (value) => {
-
-}
+const handleInputChange = (value) => {};
 
 /**
  * 文件数据变化
  * @param fileList
  */
 const handleFileChange = (fileList) => {
-    file_list.value = fileList;
-}
+  file_list.value = fileList;
+};
 
 /**
  * 文件上传操作
  */
 const getFIleParams = () => {
-    const formData = new FormData();
+  const formData = new FormData();
 
-    const f_list = file_list.value;
+  const f_list = file_list.value;
 
-    f_list.forEach((item) => {
-        const file = item.file;
+  f_list.forEach((item) => {
+    const file = item.file;
 
-        formData.append("file", file);
-    });
+    formData.append('file', file);
+  });
 
-    return formData;
-}
+  return formData;
+};
 
 const showMsg = (msg) => {
-    Message.error({ content: msg, position: 'top' });
-}
+  Message.error({ content: msg, position: 'top' });
+};
 
 /**
  * 点击开始按钮
@@ -142,147 +147,145 @@ const showMsg = (msg) => {
  * 2. 开始对话
  */
 const handleStart = async () => {
-    const action_type = act_type.value; // 操作类型
-    const title = textValue.value; // 标题
-    const f_list = file_list.value;
-
-    if (!action_type) {
-        // Message.error({ content: '请选择类型', position: 'bottom' });
-        showMsg('请选择类型');
-        return;
-    }
-
-    if (!title) {
-        // Message.error({ content: '请填写标题', position: 'bottom' });
-        showMsg('请填写标题');
-        return;
-    }
-
-    if (f_list.length === 0) {
-        // Message.error({ content: '请选择文件', position: 'bottom' });
-        showMsg('请选择文件');
-        return;
-    }
-
-
-    const agent_id = props.agentId;
-
-    try {
-        // 进行中
-        start_status.value = 2;
-        start_message.value = 'loading';
-
-        // // 创建会话
-        // const dialog = await ajax.message.createDialog(agent_id);
-
-        // const chat_id = dialog.chat_id;
-
-        // 文件参数数据
-        const fm_data = getFIleParams();
-
-        const uploadResult1 = await ajax.file.uploadFiles(agent_id, fm_data);
-        // console.log(uploadResult1, '上传结果');
-
-        // const uploadResult2 = await ajax.file.uploadFile(agent_id, chat_id, fm_data);
-        // console.log(uploadResult2, '上传结果');
-
-        // if (uploadResult2.code !== 200) {
-        //     // 失败: 接口值不为 200,接口异常
-        //     start_status.value = 4;
-        //     start_message.value = uploadResult2.msg;
-        //     return;
-        // }
-
-        // console.log(uploadResult2, '文件上传结果');
-        const files_info = uploadResult1.files; // 数组
-        const file_id_list = files_info.map(item => item.id);
-        // console.log(file_id_list, '文件ID值');
-
-        // 保存小数绘图数据
-        helper.write('sendData', {
-            name: '文档报告生成',
-
-            agent_id: agent_id,
-            // chat_id: chat_id,
-
-            upload_files: file_id_list,
-            title: title,
-            workflow: action_type,
-        });
-
-        // helper.$bus.emit('send-message', {
-        //     upload_files: file_id_list,
-        //     title: title,
-        //     workflow: action_type,
-        // });
+  const action_type = act_type.value; // 操作类型
+  const title = textValue.value; // 标题
+  const f_list = file_list.value;
+
+  if (!action_type) {
+    // Message.error({ content: '请选择类型', position: 'bottom' });
+    showMsg('请选择类型');
+    return;
+  }
+
+  if (!title) {
+    // Message.error({ content: '请填写标题', position: 'bottom' });
+    showMsg('请填写标题');
+    return;
+  }
+
+  if (f_list.length === 0) {
+    // Message.error({ content: '请选择文件', position: 'bottom' });
+    showMsg('请选择文件');
+    return;
+  }
+
+  const agent_id = props.agentId;
+
+  try {
+    // 进行中
+    start_status.value = 2;
+    start_message.value = 'loading';
+
+    // // 创建会话
+    // const dialog = await ajax.message.createDialog(agent_id);
+
+    // const chat_id = dialog.chat_id;
+
+    // 文件参数数据
+    const fm_data = getFIleParams();
+
+    const uploadResult1 = await ajax.file.uploadFiles(agent_id, fm_data);
+    // console.log(uploadResult1, '上传结果');
+
+    // const uploadResult2 = await ajax.file.uploadFile(agent_id, chat_id, fm_data);
+    // console.log(uploadResult2, '上传结果');
+
+    // if (uploadResult2.code !== 200) {
+    //     // 失败: 接口值不为 200,接口异常
+    //     start_status.value = 4;
+    //     start_message.value = uploadResult2.msg;
+    //     return;
+    // }
+
+    // console.log(uploadResult2, '文件上传结果');
+    const files_info = uploadResult1.files; // 数组
+    const file_id_list = files_info.map((item) => item.id);
+    // console.log(file_id_list, '文件ID值');
+
+    // 保存小数绘图数据
+    helper.write('sendData', {
+      name: '文档报告生成',
+
+      agent_id: agent_id,
+      // chat_id: chat_id,
+
+      upload_files: file_id_list,
+      title: title,
+      workflow: action_type
+    });
 
-        // helper.$bus.emit('send-message', title);
-        helper.$bus.emit('open-dialog', title);
+    // helper.$bus.emit('send-message', {
+    //     upload_files: file_id_list,
+    //     title: title,
+    //     workflow: action_type,
+    // });
 
+    // helper.$bus.emit('send-message', title);
+    helper.$bus.emit('open-dialog', title);
 
-        // 上传成功
-        start_status.value = 3;
-        start_message.value = 'success';
-    } catch (err) {
-        console.log(err);
+    // 上传成功
+    start_status.value = 3;
+    start_message.value = 'success';
+  } catch (err) {
+    console.log(err);
 
-        start_status.value = 5;
-        start_message.value = err.message;
-    }
-}
+    start_status.value = 5;
+    start_message.value = err.message;
+  }
+};
 
 const upload_warning_text = `支持上传文件pdf、docx文档(最多${MAX_ACCEPT_FILE}个,每个大小不超过10MB)`;
-const radio_qingxi_text = "对上传的文档进行清洗,输出生成清洗后的文档";
-const radio_shengcheng_text = "对上传的(经过清洗的)文档生成报告,输出生成的报告文档"
+const radio_qingxi_text = '对上传的文档进行清洗,输出生成清洗后的文档';
+const radio_shengcheng_text = '对上传的(经过清洗的)文档生成报告,输出生成的报告文档';
 </script>
 <style lang="scss" scoped>
 .vertical-placeholder {
-    height: 10px;
+  height: 10px;
 }
 
 .upload-footer {
-    margin-bottom: 50px;
-    padding: 20px;
-    width: 540px;
-    border: 1px solid #eee;
+  margin-bottom: 50px;
+  padding: 20px;
+  width: 540px;
+  border: 1px solid #eee;
 }
 
 .attention-requred {
-    color: red;
+  color: red;
 }
 
 .wendangbaogaoshengcheng-footer {
-    min-height: 240px;
+  min-height: 240px;
 }
 
 .max-limit-warning {
-    font-size: 12px;
+  font-size: 12px;
 }
 
-.upload-button{
-    background-color: rgb(var(--primary-6));
-    color: #fff;
+.upload-button {
+  background-color: rgb(var(--primary-6));
+  color: #fff;
 }
 
 .upload-button:hover {
-    background-color: rgb(var(--primary-5));
-    color: #fff;
+  background-color: rgb(var(--primary-5));
+  color: #fff;
 }
 </style>
 <style>
 .wendangbaogaoshengcheng-footer .arco-upload-icon.arco-upload-icon-start {
-    display: none;
+  display: none;
 }
 
 .wendangbaogaoshengcheng-footer .arco-upload-progress {
-    display: none;
+  display: none;
 }
 
 .wendangbaogaoshengcheng-footer .arco-upload-list.arco-upload-list-type-text,
-.wendangbaogaoshengcheng-footer .arco-upload-list.arco-upload-list-type-picture{
-    width: 100%;
-    max-height: 400px;
-    overflow-y: auto;
-    padding-right: 5px;
+.wendangbaogaoshengcheng-footer .arco-upload-list.arco-upload-list-type-picture {
+  width: 100%;
+  max-height: 400px;
+  overflow-y: auto;
+  padding-right: 5px;
 }
 </style>

+ 112 - 68
src/components/History.vue

@@ -2,24 +2,35 @@
   <main>
     <header>
       <p>历史记录</p>
-      <div v-outside="() => {
-        openSearch = false;
-      }
-        ">
+      <div
+        v-outside="
+          () => {
+            openSearch = false;
+          }
+        "
+      >
         <div :class="{ close: openSearch }" @click="setNewDialog">
           <img src="@/assets/history/plus.svg" width="20" />
           <span v-show="!openSearch">新建对话</span>
         </div>
         <a-tooltip content="搜索">
-          <div @click="() => {
-            openSearch = true;
-          }
-            " :class="{ 'search-hide': openSearch }">
+          <div
+            @click="
+              () => {
+                openSearch = true;
+              }
+            "
+            :class="{ 'search-hide': openSearch }"
+          >
             <img src="@/assets/history/search.svg" width="24" />
           </div>
         </a-tooltip>
-        <a-input :style="{ flex: 1, borderRadius: '19px', height: '38px' }" placeholder="搜索历史记录" allow-clear
-          v-show="openSearch">
+        <a-input
+          :style="{ flex: 1, borderRadius: '19px', height: '38px' }"
+          placeholder="搜索历史记录"
+          allow-clear
+          v-show="openSearch"
+        >
           <template #prefix>
             <icon-search />
           </template>
@@ -36,8 +47,12 @@
     </div>
     <div v-else>
       <section v-show="list.filter((v) => v.isTop).length > 0">
-        <div v-for="(item, key) in list.filter((v) => v.isTop)" :key="key"
-          :class="{ 'div-padding': openDeletes, active: selectId === item.id }" @click="handleClick(item.id)">
+        <div
+          v-for="(item, key) in list.filter((v) => v.isTop)"
+          :key="key"
+          :class="{ 'div-padding': openDeletes, active: selectId === item.id }"
+          @click="handleClick(item.id)"
+        >
           <em v-if="openDeletes" @click="setSelect(item.id)" :class="{ 'select-icon': true, active: item.isSelected }">
             <img src="@/assets/history/ok.svg" width="10" />
           </em>
@@ -60,12 +75,19 @@
                     <p>删除后无法恢复,您是否删除?</p>
                     <div class="delete-buttons">
                       <div>
-                        <a-button size="mini" type="primary" style="margin-right: 10px"
-                          @click="deleteItem(item.id)">确认</a-button>
-                        <a-button size="mini" type="outline" @click="() => {
-                          showDeleteTooltip = false;
-                        }
-                          ">取消</a-button>
+                        <a-button size="mini" type="primary" style="margin-right: 10px" @click="deleteItem(item.id)"
+                          >确认</a-button
+                        >
+                        <a-button
+                          size="mini"
+                          type="outline"
+                          @click="
+                            () => {
+                              showDeleteTooltip = false;
+                            }
+                          "
+                          >取消</a-button
+                        >
                       </div>
                     </div>
                   </template>
@@ -76,8 +98,12 @@
         </div>
       </section>
       <section>
-        <div v-for="(item, key) in list.filter((v) => !v.isTop)" :key="key"
-          :class="{ 'div-padding': openDeletes, active: selectId === item.id }" @click="handleClick(item.id)">
+        <div
+          v-for="(item, key) in list.filter((v) => !v.isTop)"
+          :key="key"
+          :class="{ 'div-padding': openDeletes, active: selectId === item.id }"
+          @click="handleClick(item.id)"
+        >
           <em v-if="openDeletes" @click="setSelect(item.id)" :class="{ 'select-icon': true, active: item.isSelected }">
             <img src="@/assets/history/ok.svg" width="10" />
           </em>
@@ -100,12 +126,19 @@
                     <p>删除后无法恢复,您是否删除?</p>
                     <div class="delete-buttons">
                       <div>
-                        <a-button size="mini" type="primary" style="margin-right: 10px"
-                          @click="deleteItem(item.id)">确认</a-button>
-                        <a-button size="mini" type="outline" @click="() => {
-                          showDeleteTooltip = false;
-                        }
-                          ">取消</a-button>
+                        <a-button size="mini" type="primary" style="margin-right: 10px" @click="deleteItem(item.id)"
+                          >确认</a-button
+                        >
+                        <a-button
+                          size="mini"
+                          type="outline"
+                          @click="
+                            () => {
+                              showDeleteTooltip = false;
+                            }
+                          "
+                          >取消</a-button
+                        >
                       </div>
                     </div>
                   </template>
@@ -117,10 +150,14 @@
       </section>
     </div>
     <footer v-if="list.length > 0 && false">
-      <div @click="() => {
-        openDeletes = true;
-      }
-        " v-if="!openDeletes">
+      <div
+        @click="
+          () => {
+            openDeletes = true;
+          }
+        "
+        v-if="!openDeletes"
+      >
         <icon-delete />
         <span>批量删除</span>
       </div>
@@ -133,18 +170,25 @@
         </div>
         <div>
           <a-popover :popup-visible="showDeleteTooltip">
-            <a-button size="mini" type="primary" status="danger" style="margin-right: 10px"
-              @click="handleDeleteButton">删除</a-button>
+            <a-button size="mini" type="primary" status="danger" style="margin-right: 10px" @click="handleDeleteButton"
+              >删除</a-button
+            >
             <template #content>
               <div>
                 <p>删除后无法恢复,您是否删除?</p>
                 <div class="delete-buttons">
                   <div>
                     <a-button size="mini" type="primary" style="margin-right: 10px" @click="deleteItems">确认</a-button>
-                    <a-button size="mini" type="outline" @click="() => {
-                      showDeleteTooltip = false;
-                    }
-                      ">取消</a-button>
+                    <a-button
+                      size="mini"
+                      type="outline"
+                      @click="
+                        () => {
+                          showDeleteTooltip = false;
+                        }
+                      "
+                      >取消</a-button
+                    >
                   </div>
                 </div>
               </div>
@@ -157,16 +201,16 @@
   </main>
 </template>
 <script>
-import { defineComponent, inject, onMounted, ref } from "vue";
+import { defineComponent, inject, onMounted, ref } from 'vue';
 export default defineComponent({
-  props: ["selectId", "list"],
+  props: ['selectId', 'list'],
   setup(props, { emit }) {
-    const { helper } = inject("$global");
+    const { helper } = inject('$global');
     const openSearch = ref(false);
     const openDeletes = ref(false);
     const isAllSelected = ref(false);
     const showDeleteTooltip = ref(false);
-    const deleteId = ref("");
+    const deleteId = ref('');
     const setTop = (isTop, id) => {
       const index = list.value.findIndex((item) => item.id === id);
       list.value[index].isTop = isTop;
@@ -211,10 +255,10 @@ export default defineComponent({
       wrapDiv.style.height = `${height}px`;
       wrapDiv.style.top = `${top}px`;
       wrapDiv.style.left = `${left}px`;
-      wrapDiv.style.position = "absolute";
-      const inputNode = document.createElement("input");
+      wrapDiv.style.position = 'absolute';
+      const inputNode = document.createElement('input');
       inputNode.value = list.value[index].content;
-      inputNode.style = "width: 100%;height: 100%";
+      inputNode.style = 'width: 100%;height: 100%';
       wrapDiv.append(inputNode);
       helper.setDialog(
         true,
@@ -228,10 +272,10 @@ export default defineComponent({
       );
     };
     const setNewDialog = () => {
-      emit("set-new");
+      emit('set-new');
     };
     const handleClick = (id) => {
-      emit("handle-click", id);
+      emit('handle-click', id);
     };
     return {
       openSearch,
@@ -276,7 +320,7 @@ main {
     align-items: center;
     flex-shrink: 0;
 
-    >img {
+    > img {
       display: none;
     }
 
@@ -284,17 +328,17 @@ main {
       background: #00aea3;
       border: 1px solid #00aea3;
 
-      >img {
+      > img {
         display: block;
       }
     }
   }
 
-  >footer {
+  > footer {
     padding: 0 16px;
     margin-bottom: 20px;
 
-    >div {
+    > div {
       padding: 4px 8px;
       border-radius: 4px;
       display: inline-flex;
@@ -310,12 +354,12 @@ main {
       }
     }
 
-    >section {
+    > section {
       display: flex;
       align-items: center;
       justify-content: space-between;
 
-      >div {
+      > div {
         display: flex;
         align-items: center;
 
@@ -326,8 +370,8 @@ main {
     }
   }
 
-  >header {
-    >p {
+  > header {
+    > p {
       padding: 0 16px;
       height: 52px;
       font-size: 18px;
@@ -335,7 +379,7 @@ main {
       font-weight: bold;
     }
 
-    >div {
+    > div {
       margin: 20px 16px 20px;
       gap: 24px;
       line-height: 42px;
@@ -343,7 +387,7 @@ main {
       align-items: center;
       display: flex;
 
-      >div {
+      > div {
         &:nth-child(1) {
           color: #f6f8ff;
           justify-content: center;
@@ -397,14 +441,14 @@ main {
     }
   }
 
-  >p {
+  > p {
     font-size: 13px;
     font-weight: 700;
     color: #7a7b7f;
     margin-left: 16px;
   }
 
-  >div {
+  > div {
     flex: 1;
     padding: 0 16px;
     overflow-y: auto;
@@ -414,13 +458,13 @@ main {
       align-items: center;
       justify-content: center;
 
-      >div {
-        >img {
+      > div {
+        > img {
           display: block;
           margin: 0 auto;
         }
 
-        >p {
+        > p {
           text-align: center;
           color: #a4a6ab;
           line-height: 20px;
@@ -429,14 +473,14 @@ main {
       }
     }
 
-    >section {
+    > section {
       overflow-y: auto;
 
       &:first-child {
         border-bottom: 1px solid #e3e3e3;
       }
 
-      >div {
+      > div {
         padding: 8px 0;
         cursor: pointer;
         overflow: hidden;
@@ -447,7 +491,7 @@ main {
           padding-left: 20px;
         }
 
-        >em {
+        > em {
           position: absolute;
           top: 30px;
           left: 0;
@@ -459,13 +503,13 @@ main {
           }
         }
 
-        >div {
+        > div {
           &:hover {
             p {
               color: #31c4c9 !important;
 
               &:nth-child(2) {
-                >span {
+                > span {
                   &:nth-child(2) {
                     opacity: 1;
                   }
@@ -474,7 +518,7 @@ main {
             }
           }
 
-          >p {
+          > p {
             height: 28px;
             line-height: 28px;
             white-space: nowrap;
@@ -487,7 +531,7 @@ main {
               display: flex;
               align-items: center;
 
-              >span {
+              > span {
                 &:nth-child(1) {
                   flex: 1;
                 }
@@ -496,7 +540,7 @@ main {
                   opacity: 0;
                   display: flex;
 
-                  >em {
+                  > em {
                     color: #000 !important;
                     display: flex;
                     width: 25px;

+ 41 - 42
src/components/Introduction.vue

@@ -1,15 +1,15 @@
 <template>
   <main>
     <section>
-      <p>{{newData.title}}</p>
+      <p>{{ newData.title }}</p>
       <div v-for="(item, key) in newData.contents" :key="key">
-        <p>{{item.title}}</p>
+        <p>{{ item.title }}</p>
         <div v-if="item.content">
-          <p>{{item.content}}</p>
+          <p>{{ item.content }}</p>
         </div>
         <div v-else>
           <p v-for="(content, index) in item.contents" :key="index">
-            {{content}}
+            {{ content }}
           </p>
         </div>
       </div>
@@ -18,13 +18,13 @@
   </main>
 </template>
 <script>
-import { defineComponent, ref } from 'vue'
-import MessageInput from '../components/MessageInput.vue'
+import { defineComponent, ref } from 'vue';
+import MessageInput from '../components/MessageInput.vue';
 export default defineComponent({
   components: {
     MessageInput
   },
-  props: [ 'data' ],
+  props: ['data'],
   setup(props) {
     const newData = ref({
       title: props.data.type,
@@ -40,51 +40,50 @@ export default defineComponent({
         {
           title: '关键词',
           contents: props.data.tags
-
         }
       ]
     });
     return {
       newData
-    }
-  },
-})
+    };
+  }
+});
 </script>
 <style scoped>
-  main {
-    margin: 20px 16px;
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
-    height: 100%;
-    padding-bottom: 20px;
-    >section {
-      flex: 1;
-      overflow-y: auto;
-      >p {
-        display: inline-block;
-        border-radius: 4px;
-        background-color: rgba(136, 176, 75, 0.1);
-        color: rgba(136, 176, 75, 1);
-        font-size: 12px;
-        padding: 4px 16px;
+main {
+  margin: 20px 16px;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  height: 100%;
+  padding-bottom: 20px;
+  > section {
+    flex: 1;
+    overflow-y: auto;
+    > p {
+      display: inline-block;
+      border-radius: 4px;
+      background-color: rgba(136, 176, 75, 0.1);
+      color: rgba(136, 176, 75, 1);
+      font-size: 12px;
+      padding: 4px 16px;
+      font-weight: bold;
+    }
+    > div {
+      margin-top: 24px;
+      > p {
+        color: rgba(51, 51, 51, 1);
+        font-size: 14px;
         font-weight: bold;
       }
-      >div {
-        margin-top: 24px;
-        >p {
-          color: rgba(51, 51, 51, 1);
-          font-size: 14px;
-          font-weight: bold;
-        }
-        >div {
-          margin-top: 8px;
-          >p {
-            color: rgba(16, 16, 16, 1);
-            font-size: 12px;
-          }
+      > div {
+        margin-top: 8px;
+        > p {
+          color: rgba(16, 16, 16, 1);
+          font-size: 12px;
         }
       }
     }
   }
-</style>
+}
+</style>

+ 118 - 115
src/components/MessageInput.vue

@@ -1,148 +1,151 @@
 <template>
-    <div class="message-input-wrap">
-        <div class="message-input-border">
-            <div class="message-input-clear" @click="clearMessage">
-                <div :class="[readonly ? 'disabled' : '']">
-                    <img src="@/assets/icons/iconPark-clear.svg" width="15" />
-                </div>
-            </div>
-            <a-textarea 
-                @keydown.enter="handleEnter" 
-                :max-length="maxLength" 
-                v-model="value"
-                :show-word-limit="value.length > maxLength / 2" 
-                :auto-size="{ maxRows: 6 }" 
-                :disabled="readonly"
-                placeholder="输入您想了解的内容,Shift+Enter换行" 
-                :style="{
-                    flex: 1,
-                    borderRadius: '12px',
-                    marginTop: '20px',
-                    padding: '0px 30px 0 16px',
-                    background: 'transparent',
-                    border: '1px solid #e3e3e3',
-                    minHeight: '120px',
-                    paddingBottom: `${value.length > maxLength / 2 ? '20px' : ''}`
-                }">
-            </a-textarea>
-        </div>
-        <div :class="['message-button', 'message-button-send', value.length > 0 && !readonly ? '' : 'disabled']"
-            @click="sendMessage">
-            <icon-send size="30" />
+  <div class="message-input-wrap">
+    <div class="message-input-border">
+      <div class="message-input-clear" @click="clearMessage">
+        <div :class="[readonly ? 'disabled' : '']">
+          <img src="@/assets/icons/iconPark-clear.svg" width="15" />
         </div>
+      </div>
+      <a-textarea
+        @keydown.enter="handleEnter"
+        :max-length="maxLength"
+        v-model="value"
+        :show-word-limit="value.length > maxLength / 2"
+        :auto-size="{ maxRows: 6 }"
+        :disabled="readonly"
+        placeholder="输入您想了解的内容,Shift+Enter换行"
+        :style="{
+          flex: 1,
+          borderRadius: '12px',
+          marginTop: '20px',
+          padding: '0px 30px 0 16px',
+          background: 'transparent',
+          border: '1px solid #e3e3e3',
+          minHeight: '120px',
+          paddingBottom: `${value.length > maxLength / 2 ? '20px' : ''}`
+        }"
+      >
+      </a-textarea>
+    </div>
+    <div
+      :class="['message-button', 'message-button-send', value.length > 0 && !readonly ? '' : 'disabled']"
+      @click="sendMessage"
+    >
+      <icon-send size="30" />
     </div>
+  </div>
 </template>
 <script>
-import { defineComponent, ref, inject, onMounted, onBeforeUnmount } from "vue";
+import { defineComponent, ref, inject, onMounted, onBeforeUnmount } from 'vue';
 export default defineComponent({
-    components: {},
-    props: ["readonly", "eventName"],
-    setup(props) {
-        const { helper } = inject("$global");
-        const value = ref("");
-        const maxLength = ref(6000);
-        const sendMessage = () => {
-            if (value.value.length > 0 && !props.readonly) {
-                const eventName = props.eventName || "send-message";
-                helper.$bus.emit(eventName, value.value);
-                value.value = "";
-            }
-        };
-        const clearMessage = () => {
-            if (!props.readonly) {
-                helper.$bus.emit("clear-message");
-            }
-        };
-        const handleEnter = (e) => {
-            if (!e.shiftKey) {
-                e.preventDefault();
-                sendMessage();
-            }
-        };
-        onMounted(() => {
-            helper.$bus.on("set-input", (data) => {
-                value.value = data;
-            });
-        });
-        onBeforeUnmount(() => {
-            helper.$bus.off("set-input");
-        });
-        return {
-            value,
-            maxLength,
-            readonly: props.readonly,
-            sendMessage,
-            clearMessage,
-            handleEnter
-        };
-    }
+  components: {},
+  props: ['readonly', 'eventName'],
+  setup(props) {
+    const { helper } = inject('$global');
+    const value = ref('');
+    const maxLength = ref(6000);
+    const sendMessage = () => {
+      if (value.value.length > 0 && !props.readonly) {
+        const eventName = props.eventName || 'send-message';
+        helper.$bus.emit(eventName, value.value);
+        value.value = '';
+      }
+    };
+    const clearMessage = () => {
+      if (!props.readonly) {
+        helper.$bus.emit('clear-message');
+      }
+    };
+    const handleEnter = (e) => {
+      if (!e.shiftKey) {
+        e.preventDefault();
+        sendMessage();
+      }
+    };
+    onMounted(() => {
+      helper.$bus.on('set-input', (data) => {
+        value.value = data;
+      });
+    });
+    onBeforeUnmount(() => {
+      helper.$bus.off('set-input');
+    });
+    return {
+      value,
+      maxLength,
+      readonly: props.readonly,
+      sendMessage,
+      clearMessage,
+      handleEnter
+    };
+  }
 });
 </script>
 <style scoped>
 .message-input-border {
-    display: flex;
+  display: flex;
 }
 
 .message-input-clear {
-    width: 30px;
-    height: 100%;
-    margin-right: 8px;
-    display: none;
+  width: 30px;
+  height: 100%;
+  margin-right: 8px;
+  display: none;
 
-    div {
-        width: 30px;
-        height: 30px;
-        border-radius: 15px;
-        background-color: rgba(64, 95, 234, 0.05);
-        position: absolute;
-        bottom: 0;
-        cursor: pointer;
-        display: flex;
-        align-items: center;
-        justify-content: center;
+  div {
+    width: 30px;
+    height: 30px;
+    border-radius: 15px;
+    background-color: rgba(64, 95, 234, 0.05);
+    position: absolute;
+    bottom: 0;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 
-        &.disabled {
-            cursor: not-allowed;
-        }
+    &.disabled {
+      cursor: not-allowed;
+    }
 
-        &:hover {
-            background-color: rgba(64, 95, 234, 0.1);
-        }
+    &:hover {
+      background-color: rgba(64, 95, 234, 0.1);
     }
+  }
 }
 
 .message-input-wrap {
-    position: relative;
-    margin-bottom: 20px;
+  position: relative;
+  margin-bottom: 20px;
 }
 
 .message-button {
-    position: absolute;
-    width: 30px;
-    height: 40px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    bottom: 5px;
-    right: 5px;
-    z-index: 2;
+  position: absolute;
+  width: 30px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  bottom: 5px;
+  right: 5px;
+  z-index: 2;
 
-    &.disabled {
-        opacity: 0.5;
-        cursor: not-allowed;
-    }
+  &.disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+  }
 }
 
 .message-button-upload {
-    left: 38px;
+  left: 38px;
 }
 
 .message-button-send {
-    color: rgb(64, 95, 234, 0.8);
+  color: rgb(64, 95, 234, 0.8);
 
-    &:hover {
-        color: rgb(64, 95, 234);
-    }
+  &:hover {
+    color: rgb(64, 95, 234);
+  }
 }
 </style>

+ 95 - 95
src/components/NormalCards.vue

@@ -1,13 +1,13 @@
 <template>
-    <main>
-        <header>
-            <!-- <p>试一试这样问我:</p>
+  <main>
+    <header>
+      <!-- <p>试一试这样问我:</p>
             <a-button size="small" type="outline" shape="round" @click="changeCards"
                 ><template #icon> <icon-swap /> </template>换一换</a-button
             > -->
-        </header>
-        <section>
-            <!-- <div
+    </header>
+    <section>
+      <!-- <div
                 v-for="(item, key) in listData"
                 :key="key"
                 :class="{ rotate: isRotate, 'no-rotate': isOver }"
@@ -19,106 +19,106 @@
                 </div>
                 <p>{{ item.content }}</p>
             </div> -->
-        </section>
-    </main>
+    </section>
+  </main>
 </template>
 <script>
-import { defineComponent, inject, ref } from "vue";
+import { defineComponent, inject, ref } from 'vue';
 export default defineComponent({
-    props: ["data"],
-    setup(props) {
-        const { helper } = inject("$global");
-        const isTest = ref(true);
-        const isRotate = ref(false);
-        const isOver = ref(false);
-        const selectCard = (data) => {
-            helper.$bus.emit("set-input", data);
-        };
-        const listData = ref(props.data);
-        const changeCards = () => {
-            isRotate.value = true;
-            setTimeout(() => {
-                listData.value = helper.shuffleArray(listData.value);
-                isTest.value = !isTest.value;
-                isOver.value = true;
-                isRotate.value = false;
-            }, 500);
-            setTimeout(() => {
-                isOver.value = false;
-            }, 550);
-        };
-        return { listData, changeCards, isRotate, isOver, selectCard };
-    }
+  props: ['data'],
+  setup(props) {
+    const { helper } = inject('$global');
+    const isTest = ref(true);
+    const isRotate = ref(false);
+    const isOver = ref(false);
+    const selectCard = (data) => {
+      helper.$bus.emit('set-input', data);
+    };
+    const listData = ref(props.data);
+    const changeCards = () => {
+      isRotate.value = true;
+      setTimeout(() => {
+        listData.value = helper.shuffleArray(listData.value);
+        isTest.value = !isTest.value;
+        isOver.value = true;
+        isRotate.value = false;
+      }, 500);
+      setTimeout(() => {
+        isOver.value = false;
+      }, 550);
+    };
+    return { listData, changeCards, isRotate, isOver, selectCard };
+  }
 });
 </script>
 <style lang="scss" scoped>
 main {
-    height: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  > header {
     display: flex;
-    flex-direction: column;
-    overflow: hidden;
-    > header {
-        display: flex;
-        justify-content: space-between;
-        margin-bottom: 18px;
-        > p {
-            color: #7f7f7f;
-        }
+    justify-content: space-between;
+    margin-bottom: 18px;
+    > p {
+      color: #7f7f7f;
     }
-    > section {
-        overflow-y: auto;
+  }
+  > section {
+    overflow-y: auto;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px;
+    > div {
+      width: calc(33.33333% - 13.33333px);
+      height: 128px;
+      background: #f6fbfd;
+      border-radius: 12px;
+      cursor: pointer;
+      transition: all 0.5s linear;
+      &.no-rotate {
+        transform-style: flat;
+        transition-duration: 0.5s;
+        opacity: 1;
+      }
+      &.rotate {
+        transform-style: preserve-3d;
+        transform: rotateY(180deg);
+        opacity: 0;
+      }
+      &:hover {
+        background: #e9f7f8;
+      }
+      > div {
         display: flex;
-        flex-wrap: wrap;
-        gap: 12px;
-        > div {
-            width: calc(33.33333% - 13.33333px);
-            height: 128px;
-            background: #f6fbfd;
-            border-radius: 12px;
-            cursor: pointer;
-            transition: all 0.5s linear;
-            &.no-rotate {
-                transform-style: flat;
-                transition-duration: 0.5s;
-                opacity: 1;
-            }
-            &.rotate {
-                transform-style: preserve-3d;
-                transform: rotateY(180deg);
-                opacity: 0;
-            }
-            &:hover {
-                background: #e9f7f8;
-            }
-            > div {
-                display: flex;
-                align-items: center;
-                margin: 24px 20px 12px;
-                > img {
-                    width: 28px;
-                    height: 28px;
-                    margin-right: 12px;
-                }
-                > p {
-                    font-size: 18px;
-                    font-weight: 600;
-                    color: #000;
-                }
-            }
-            > p {
-                font-size: 15px;
-                font-family: MiSans;
-                font-weight: 400;
-                color: #7a7d7e;
-                margin: 0 20px;
-                overflow: hidden;
-                text-overflow: ellipsis;
-                display: -webkit-box;
-                -webkit-line-clamp: 2;
-                -webkit-box-orient: vertical;
-                line-height: 1.4;
-            }
+        align-items: center;
+        margin: 24px 20px 12px;
+        > img {
+          width: 28px;
+          height: 28px;
+          margin-right: 12px;
+        }
+        > p {
+          font-size: 18px;
+          font-weight: 600;
+          color: #000;
         }
+      }
+      > p {
+        font-size: 15px;
+        font-family: MiSans;
+        font-weight: 400;
+        color: #7a7d7e;
+        margin: 0 20px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-line-clamp: 2;
+        -webkit-box-orient: vertical;
+        line-height: 1.4;
+      }
     }
+  }
 }
 </style>

+ 12 - 12
src/components/PictureFooter.vue

@@ -1,26 +1,26 @@
 <template>
-<footer>
+  <footer>
     <div class="btn-container">
-        <PictureUpload :agentId="agentId"/>
+      <PictureUpload :agentId="agentId" />
     </div>
-    
+
     <PictureMessageInput />
-</footer>
+  </footer>
 </template>
 <script setup>
-import {onMounted, watch} from 'vue'
-import PictureUpload from './PictureUpload.vue'
-import PictureMessageInput from './PictureMessageInput.vue'
+import { onMounted, watch } from 'vue';
+import PictureUpload from './PictureUpload.vue';
+import PictureMessageInput from './PictureMessageInput.vue';
 
 const props = defineProps({
-    agentId: String,
+  agentId: String
 });
 </script>
 
 <style lang="scss" scoped>
-.btn-container{
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
+.btn-container {
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
 }
 </style>

+ 105 - 96
src/components/PictureMessageInput.vue

@@ -1,79 +1,88 @@
 <template>
-    <div class="message-input-wrap">
-        <div class="message-input-border">
-            <div class="message-input-clear" @click="clearMessage">
-                <div :class="[readonly ? 'disabled' : '']">
-                    <img src="@/assets/icons/iconPark-clear.svg" width="15" />
-                </div>
-            </div>
-            <a-textarea @keydown.enter="handleEnter" :max-length="maxLength" v-model="value"
-                :show-word-limit="value.length > maxLength / 2" :auto-size="{ maxRows: 6 }" :disabled="readonly"
-                placeholder="输入您想了解的内容,Shift+Enter换行" :style="{
-                    flex: 1,
-                    borderRadius: '12px',
-                    marginTop: '20px',
-                    padding: '0px 30px 0 16px',
-                    background: 'transparent',
-                    border: '1px solid #e3e3e3',
-                    minHeight: '120px',
-                    paddingBottom: `${value.length > maxLength / 2 ? '20px' : ''}`
-                }">
-            </a-textarea>
-        </div>
-        <div :class="['message-button', 'message-button-send', value.length > 0 && !readonly ? '' : 'disabled']"
-            @click="sendMessage">
-            <icon-send size="30" />
+  <div class="message-input-wrap">
+    <div class="message-input-border">
+      <div class="message-input-clear" @click="clearMessage">
+        <div :class="[readonly ? 'disabled' : '']">
+          <img src="@/assets/icons/iconPark-clear.svg" width="15" />
         </div>
+      </div>
+      <a-textarea
+        @keydown.enter="handleEnter"
+        :max-length="maxLength"
+        v-model="value"
+        :show-word-limit="value.length > maxLength / 2"
+        :auto-size="{ maxRows: 6 }"
+        :disabled="readonly"
+        placeholder="输入您想了解的内容,Shift+Enter换行"
+        :style="{
+          flex: 1,
+          borderRadius: '12px',
+          marginTop: '20px',
+          padding: '0px 30px 0 16px',
+          background: 'transparent',
+          border: '1px solid #e3e3e3',
+          minHeight: '120px',
+          paddingBottom: `${value.length > maxLength / 2 ? '20px' : ''}`
+        }"
+      >
+      </a-textarea>
+    </div>
+    <div
+      :class="['message-button', 'message-button-send', value.length > 0 && !readonly ? '' : 'disabled']"
+      @click="sendMessage"
+    >
+      <icon-send size="30" />
     </div>
+  </div>
 </template>
 <script setup>
-import { defineComponent, ref, inject, onMounted, onBeforeUnmount } from "vue";
+import { defineComponent, ref, inject, onMounted, onBeforeUnmount } from 'vue';
 
 const props = defineProps({
-    readonly: Boolean,
-    eventName: String
+  readonly: Boolean,
+  eventName: String
 });
 
-const { helper } = inject("$global");
-const value = ref("");
+const { helper } = inject('$global');
+const value = ref('');
 const ask_times = ref(0);
 const maxLength = ref(6000);
 const sendMessage = () => {
-    const msg_str = value.value;
+  const msg_str = value.value;
 
-    if (msg_str.length > 0 && !props.readonly) {
-        if(ask_times.value === 0){
-            helper.$bus.emit('open-dialog', msg_str);
-        }else{
-            helper.$bus.emit('send-message', msg_str);
-        }
-
-        value.value = "";
-        ask_times.value = ask_times.value + 1;
+  if (msg_str.length > 0 && !props.readonly) {
+    if (ask_times.value === 0) {
+      helper.$bus.emit('open-dialog', msg_str);
+    } else {
+      helper.$bus.emit('send-message', msg_str);
     }
+
+    value.value = '';
+    ask_times.value = ask_times.value + 1;
+  }
 };
 
 const clearMessage = () => {
-    if (!props.readonly) {
-        helper.$bus.emit("clear-message");
-    }
+  if (!props.readonly) {
+    helper.$bus.emit('clear-message');
+  }
 };
 
 const handleEnter = (e) => {
-    if (!e.shiftKey) {
-        e.preventDefault();
-        sendMessage();
-    }
+  if (!e.shiftKey) {
+    e.preventDefault();
+    sendMessage();
+  }
 };
 
 onMounted(() => {
-    helper.$bus.on("set-input", (data) => {
-        value.value = data;
-    });
+  helper.$bus.on('set-input', (data) => {
+    value.value = data;
+  });
 });
 
 onBeforeUnmount(() => {
-    helper.$bus.off("set-input");
+  helper.$bus.off('set-input');
 });
 
 // export default defineComponent({
@@ -130,69 +139,69 @@ onBeforeUnmount(() => {
 </script>
 <style scoped>
 .message-input-border {
-    display: flex;
+  display: flex;
 }
 
 .message-input-clear {
-    width: 30px;
-    height: 100%;
-    margin-right: 8px;
-    display: none;
-
-    div {
-        width: 30px;
-        height: 30px;
-        border-radius: 15px;
-        background-color: rgba(64, 95, 234, 0.05);
-        position: absolute;
-        bottom: 0;
-        cursor: pointer;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-
-        &.disabled {
-            cursor: not-allowed;
-        }
-
-        &:hover {
-            background-color: rgba(64, 95, 234, 0.1);
-        }
-    }
-}
+  width: 30px;
+  height: 100%;
+  margin-right: 8px;
+  display: none;
 
-.message-input-wrap {
-    position: relative;
-    margin-bottom: 20px;
-}
-
-.message-button {
-    position: absolute;
+  div {
     width: 30px;
-    height: 40px;
+    height: 30px;
+    border-radius: 15px;
+    background-color: rgba(64, 95, 234, 0.05);
+    position: absolute;
+    bottom: 0;
+    cursor: pointer;
     display: flex;
     align-items: center;
     justify-content: center;
-    cursor: pointer;
-    bottom: 5px;
-    right: 5px;
-    z-index: 2;
 
     &.disabled {
-        opacity: 0.5;
-        cursor: not-allowed;
+      cursor: not-allowed;
     }
+
+    &:hover {
+      background-color: rgba(64, 95, 234, 0.1);
+    }
+  }
+}
+
+.message-input-wrap {
+  position: relative;
+  margin-bottom: 20px;
+}
+
+.message-button {
+  position: absolute;
+  width: 30px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  bottom: 5px;
+  right: 5px;
+  z-index: 2;
+
+  &.disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+  }
 }
 
 .message-button-upload {
-    left: 38px;
+  left: 38px;
 }
 
 .message-button-send {
-    color: rgb(64, 95, 234, 0.8);
+  color: rgb(64, 95, 234, 0.8);
 
-    &:hover {
-        color: rgb(64, 95, 234);
-    }
+  &:hover {
+    color: rgb(64, 95, 234);
+  }
 }
 </style>

+ 135 - 145
src/components/PictureUpload.vue

@@ -1,62 +1,60 @@
 <template>
-<footer class="picture-upload-footer">
-  <a-popover :popup-visible="showUpload" position="tl" @popup-visible-change="handlePopupChange">
-    <div class="text-hide">
-      <div class="upload-img-container" @click="handleUploadClick">
-        <img src="@/assets/document/6.svg" class="img-normal" v-if="!showUpload" />
-        <img src="@/assets/document/7.svg" class="img-hover" v-if="!showUpload" />
-        <img src="@/assets/document/8.svg" class="img-active" v-if="showUpload" />
+  <footer class="picture-upload-footer">
+    <a-popover :popup-visible="showUpload" position="tl" @popup-visible-change="handlePopupChange">
+      <div class="text-hide">
+        <div class="upload-img-container" @click="handleUploadClick">
+          <img src="@/assets/document/6.svg" class="img-normal" v-if="!showUpload" />
+          <img src="@/assets/document/7.svg" class="img-hover" v-if="!showUpload" />
+          <img src="@/assets/document/8.svg" class="img-active" v-if="showUpload" />
+        </div>
+
+        <p>{{ file_status_label_tips }}</p>
       </div>
 
-      <p>{{ file_status_label_tips }}</p>
-    </div>
+      <template #content>
+        <div :class="{ 'upload-wrap': true, 'upload-wrap-narrow': uploadFile }">
+          <header>
+            <p>{{ uploadFile ? '上传图片' : '上传图片' }}</p>
 
-    <template #content>
-      <div :class="{ 'upload-wrap': true, 'upload-wrap-narrow': uploadFile }">
-        <header>
-          <p>{{ uploadFile ? "上传图片" : "上传图片" }}</p>
+            <div @click="handleUploadClose">
+              <icon-close size="large" />
+            </div>
+          </header>
+
+          <div class="xiaoshuhuitu-image-upload">
+            <section v-if="tableData.length === 0">
+              <a-upload
+                :draggable="true"
+                list-type="picture"
+                :multiple="false"
+                :limit="1"
+                :show-file-list="false"
+                :custom-request="customRequest"
+                :show-upload-button="{ showOnExceedLimit: false }"
+                accept=".png,.jpg"
+                @before-upload="onBeforeUpload"
+                @exceed-limit="onExceedLimit"
+                @before-remove="onBeforeRemove"
+              >
+                <template #upload-button>
+                  <div class="upload-main">
+                    <p>拖拽图片到这里,或<span>点此上传</span></p>
+                    <span> 支持上传 .png, .jpg,大小不超过10M </span>
+                  </div>
+                </template>
+              </a-upload>
+            </section>
 
-          <div @click="handleUploadClose">
-            <icon-close size="large" />
-          </div>
-        </header>
-
-        <div class="xiaoshuhuitu-image-upload">
-          <section v-if="tableData.length === 0">
-            <a-upload 
-              :draggable="true"
-              list-type="picture"
-              :multiple="false" 
-              :limit="1" 
-              :show-file-list="false"
-              :custom-request="customRequest" 
-              :show-upload-button="{ showOnExceedLimit: false }"
-              accept=".png,.jpg"
-              @before-upload="onBeforeUpload" 
-              @exceed-limit="onExceedLimit" 
-              @before-remove="onBeforeRemove"
-            >
-              <template #upload-button>
-                <div class="upload-main">
-                  <p>拖拽图片到这里,或<span>点此上传</span></p>
-                  <span>
-                    支持上传 .png, .jpg,大小不超过10M
-                  </span>
-                </div>
-              </template>
-            </a-upload>
-          </section>
-
-          <!-- <div v-if="tableData.length > 0">
+            <!-- <div v-if="tableData.length > 0">
             <p>
               <span>已选择图片列表</span>
               <span>共{{ tableData.length }}个</span>
             </p>
             <div>
-              <a-table 
-                :pagination="false" 
-                row-key="name" 
-                :columns="columns" 
+              <a-table
+                :pagination="false"
+                row-key="name"
+                :columns="columns"
                 :data="tableData"
                 v-model:selectedKeys="selectedKeys"
               >
@@ -68,36 +66,36 @@
             </div>
           </div> -->
 
-          <FileListTable  
-            v-if="tableData.length > 0" 
-            :tableData="tableData" 
-            :columns="columns" 
-            :selectedKeys="selectedKeys"
-            @download="downloadDocument"
-            @delete="deleteDocument"
-          />
+            <FileListTable
+              v-if="tableData.length > 0"
+              :tableData="tableData"
+              :columns="columns"
+              :selectedKeys="selectedKeys"
+              @download="downloadDocument"
+              @delete="deleteDocument"
+            />
+          </div>
         </div>
-      </div>
 
-      <div class="bottom-buttons">
-        <div>
-          <a-button type="outline" style="margin-right: 10px" @click="handleUploadClose">取消</a-button>
+        <div class="bottom-buttons">
+          <div>
+            <a-button type="outline" style="margin-right: 10px" @click="handleUploadClose">取消</a-button>
 
-          <a-button :loading="buttonLoading" type="primary" @click="selectFiles(true, 'paper')">
-            去{{ uploadFile ? '提问' : '提问' }} ({{ fileList.length}})
-          </a-button>
+            <a-button :loading="buttonLoading" type="primary" @click="selectFiles(true, 'paper')">
+              去{{ uploadFile ? '提问' : '提问' }} ({{ fileList.length }})
+            </a-button>
+          </div>
         </div>
-      </div>
-    </template>
-  </a-popover>
+      </template>
+    </a-popover>
 
-  <span class="placeholder-width-5px"></span>
-  <BtnIframeComfyui />
-</footer>
+    <span class="placeholder-width-5px"></span>
+    <BtnIframeComfyui />
+  </footer>
 </template>
 <script>
-import dayjs from "dayjs";
-import { defineComponent, ref, inject, reactive, onBeforeUnmount, computed } from "vue";
+import dayjs from 'dayjs';
+import { defineComponent, ref, inject, reactive, onBeforeUnmount, computed } from 'vue';
 
 import { Message } from '@arco-design/web-vue';
 
@@ -110,12 +108,12 @@ import BtnImgDelete from './picture-upload/BtnImgDelete.vue';
 
 import FileListTable from './picture-upload/FileListTable.vue';
 
-import {huituSetTempImageFile} from './dialog-wrap/temp-image'
+import { huituSetTempImageFile } from './dialog-wrap/temp-image';
 
-import {useImageUploadStatus} from '../store/index';
+import { useImageUploadStatus } from '../store/index';
 
 export default defineComponent({
-  props: ["data", "uploadFile", "isQuestion", "agentId", "agengtName"],
+  props: ['data', 'uploadFile', 'isQuestion', 'agentId', 'agengtName'],
   components: {
     BtnImgDownload,
     BtnImgDelete,
@@ -126,10 +124,10 @@ export default defineComponent({
     ImgEditBtn
   },
   setup(props) {
-    const { helper, ajax } = inject("$global");
+    const { helper, ajax } = inject('$global');
 
     const imageUploadStatus = useImageUploadStatus();
-    
+
     const maxSize = 30 * 1024 * 1024;
 
     const showUpload = ref(false);
@@ -138,17 +136,17 @@ export default defineComponent({
     let formData = new FormData();
     let inputData = ref([]);
     const showDeleteTooltip = ref(false);
-    const deleteId = ref("");
+    const deleteId = ref('');
     const buttonLoading = ref(false);
 
     const file_status_label_tips = computed(() => {
       const can_upload = imageUploadStatus.canUploadContinue;
 
-      if(!can_upload){
+      if (!can_upload) {
         // 不允许上传
-        return `已保存 1 个图片`
-      }else{
-        return `已选择 ${fileList.value.length} 个图片`
+        return `已保存 1 个图片`;
+      } else {
+        return `已选择 ${fileList.value.length} 个图片`;
       }
     });
 
@@ -158,30 +156,29 @@ export default defineComponent({
     const handleUploadClick = () => {
       // 检查上一次传图后有没有发布文字,如果没有发布文字,则不允许再次上传图片
       const can_upload = imageUploadStatus.canUploadContinue;
-      if(can_upload){
+      if (can_upload) {
         // console.log('允许继续上传图片', can_upload);
-      }else{
+      } else {
         Message.warning('图片已保存,请输入文字进行提问');
         return;
       }
 
       showUpload.value = true;
-    }
+    };
 
     const handleUploadClose = () => {
       showUpload.value = false;
-    }
+    };
     const handleCancelDelete = () => {
       showDeleteTooltip.value = false;
     };
 
-
     const selectFiles = async (isSelect, type) => {
       if (isSelect) {
         if (props.uploadFile) {
           const data = await ajax.message.createDialog(props.agentId);
-          fileList.value.forEach(file => {
-            formData.append('file', file)
+          fileList.value.forEach((file) => {
+            formData.append('file', file);
           });
           buttonLoading.value = true;
           const result = await ajax.file.uploadFile(props.agentId, data.chat_id, formData);
@@ -202,18 +199,18 @@ export default defineComponent({
           inputData.value.push({
             name: result.file_name,
             file_path: result.file_path,
-            value: ""
+            value: ''
           });
 
           const sendData = {
             chatHistory: [],
             chat_id: data.chat_id,
             agent_id: props.agentId,
-            name: "小数绘图",
-            description: "小数绘图",
+            name: '小数绘图',
+            description: '小数绘图',
             inputs: {
-              report_name: inputData.value.map(item => item.name).join(', '),
-              id: "Report-PRcYL",
+              report_name: inputData.value.map((item) => item.name).join(', '),
+              id: 'Report-PRcYL',
               data: inputData.value
             }
           };
@@ -224,11 +221,9 @@ export default defineComponent({
         } else {
           // 图片上传的状态
 
-
-
           let temp_file = null;
-          fileList.value.forEach(file => {
-            formData.append('file', file)
+          fileList.value.forEach((file) => {
+            formData.append('file', file);
 
             temp_file = file;
           });
@@ -256,7 +251,7 @@ export default defineComponent({
             upload_file_id: result.id,
             mime_type: result.mime_type,
             name: result.name,
-            created_by: result.created_by,
+            created_by: result.created_by
           });
 
           // 隐藏 popover
@@ -268,8 +263,7 @@ export default defineComponent({
           tableData.length = 0;
           fileList.value = [];
         }
-      }else{
-
+      } else {
       }
     };
 
@@ -280,14 +274,14 @@ export default defineComponent({
 
     const onBeforeUpload = (file) => {
       if (file.size > maxSize) {
-        helper.message("error", `上传文件大小不能超过10M`);
+        helper.message('error', `上传文件大小不能超过10M`);
         return false;
       }
       return true;
     };
 
     const onExceedLimit = () => {
-      helper.message("error", `最多上传1个文件`);
+      helper.message('error', `最多上传1个文件`);
     };
 
     const customRequest = async (option) => {
@@ -299,7 +293,7 @@ export default defineComponent({
         name: file.name,
         type: file.type,
         size: helper.formatSize(file.size),
-        time: dayjs(file.lastModified).format("YYYY-MM-DD HH:mm:ss")
+        time: dayjs(file.lastModified).format('YYYY-MM-DD HH:mm:ss')
       });
       onSuccess();
     };
@@ -311,40 +305,40 @@ export default defineComponent({
     const selectedKeys = ref([]);
 
     const rowSelection = reactive({
-      type: "checkbox",
+      type: 'checkbox',
       showCheckedAll: true,
       onlyCurrent: false
     });
 
     const columns = [
       {
-        title: "文件名称",
-        dataIndex: "name",
+        title: '文件名称',
+        dataIndex: 'name',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "类型",
-        dataIndex: "type",
+        title: '类型',
+        dataIndex: 'type',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "大小",
-        dataIndex: "size"
+        title: '大小',
+        dataIndex: 'size'
       },
       {
-        title: "上传时间",
-        dataIndex: "time",
+        title: '上传时间',
+        dataIndex: 'time',
         ellipsis: true,
         tooltip: true,
         width: 150
       },
       {
-        title: "操作",
-        slotName: "methods"
+        title: '操作',
+        slotName: 'methods'
       }
     ];
 
@@ -361,11 +355,8 @@ export default defineComponent({
       fileList.value = [];
     };
 
-
     // 组件卸载
-    onBeforeUnmount(() => {
-
-    });
+    onBeforeUnmount(() => {});
 
     return {
       agengtName: props.agengtName,
@@ -395,7 +386,7 @@ export default defineComponent({
       handleUploadClick,
       handleUploadClose,
 
-      file_status_label_tips,
+      file_status_label_tips
     };
   }
 });
@@ -406,7 +397,7 @@ export default defineComponent({
   display: flex;
   justify-content: right;
 
-  >div {
+  > div {
     display: flex;
   }
 }
@@ -429,11 +420,11 @@ export default defineComponent({
 }
 
 /**宽度占位 */
-.placeholder-width-5px{
+.placeholder-width-5px {
   display: inline-block;
   width: 10px;
 }
-.pictures-upload-info{
+.pictures-upload-info {
   display: flex;
   align-items: center;
   justify-content: flex-start;
@@ -442,30 +433,30 @@ export default defineComponent({
 .upload-main {
   width: 800px;
   height: 109px;
-  background: url("@/assets/document/upload.svg");
+  background: url('@/assets/document/upload.svg');
   margin: 0 auto;
   padding: 24px 0px 24px 277px;
   background-size: 100%;
 
-  >p {
+  > p {
     color: #000;
     font-weight: bold;
     margin-bottom: 5px;
     margin-top: 10px;
 
-    >span {
+    > span {
       color: #00aea3;
       text-decoration: underline;
     }
   }
 
-  >span {
+  > span {
     font-size: 13px;
     color: #7f7f7f;
   }
 }
 
-footer.picture-upload-footer{
+footer.picture-upload-footer {
   display: flex;
   justify-content: flex-start;
   align-items: center;
@@ -477,7 +468,7 @@ footer.picture-upload-footer{
     align-items: center;
   }
 
-  .upload-img-container{
+  .upload-img-container {
     cursor: pointer;
     // width: 110px;
     height: 32px;
@@ -500,7 +491,7 @@ footer.picture-upload-footer{
       }
     }
 
-    >img {
+    > img {
       width: 110px;
       height: 32px;
     }
@@ -556,14 +547,13 @@ main {
   //   }
   // }
 
-
-  >footer {
+  > footer {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-top: auto;
 
-    >div {
+    > div {
       display: inline-flex;
       align-items: center;
       gap: 8px;
@@ -586,17 +576,17 @@ main {
         width: 100px;
         overflow: hidden;
 
-        >div>img {
+        > div > img {
           width: 100px;
         }
       }
 
-      >p {
+      > p {
         overflow: hidden;
         white-space: nowrap;
       }
 
-      >div {
+      > div {
         cursor: pointer;
         width: 110px;
         height: 32px;
@@ -619,21 +609,21 @@ main {
           }
         }
 
-        >img {
+        > img {
           width: 110px;
           height: 32px;
         }
       }
     }
 
-    >section {
+    > section {
       display: flex;
       align-items: center;
       background: rgba(150, 171, 185, 0.2);
       border-radius: 20px;
       padding: 5px 10px;
 
-      >p {
+      > p {
         margin-right: 5px;
       }
     }
@@ -651,18 +641,18 @@ main {
     height: auto;
   }
 
-  >header {
+  > header {
     display: flex;
     align-items: center;
     justify-content: space-between;
     margin-bottom: 13px;
 
-    >p {
+    > p {
       font-size: 18px;
       font-weight: bold;
     }
 
-    >div {
+    > div {
       width: 38px;
       height: 38px;
       border-radius: 6px;
@@ -677,12 +667,12 @@ main {
     }
   }
 
-  >div {
+  > div {
     flex: 1;
     overflow-y: auto;
 
-    >div {
-      >p {
+    > div {
+      > p {
         margin: 20px 0;
         color: #7f7f7f;
         font-size: 13px;

+ 32 - 31
src/components/ProjectIntro.vue

@@ -1,19 +1,20 @@
 <template>
-<header>
+  <header>
     <div class="project-intro-container">
-        <img class="project-logo" src="@/assets/other/robot.gif" width="52" />
+      <img class="project-logo" src="@/assets/other/robot.gif" width="52" />
 
-        <p class="project-title-p">
-            {{ SYSTEM_NAME }}<span class="project-title-highlight">{{ slider.find(item => item.id === navId).title }}</span>
-        </p>
+      <p class="project-title-p">
+        {{ SYSTEM_NAME
+        }}<span class="project-title-highlight">{{ slider.find((item) => item.id === navId).title }}</span>
+      </p>
 
-        <span class="project-slider-container">{{ slider.find(item => item.id === navId).dialog }}</span>
+      <span class="project-slider-container">{{ slider.find((item) => item.id === navId).dialog }}</span>
     </div>
-</header>
+  </header>
 </template>
 
 <script setup>
-import { inject, watch, computed, ref } from "vue";
+import { inject, watch, computed, ref } from 'vue';
 
 /**
  * 项目介绍内容组件
@@ -21,43 +22,43 @@ import { inject, watch, computed, ref } from "vue";
  * 项目介绍,特性轮播
  */
 
-const { config, helper, ajax } = inject("$global");
+const { config, helper, ajax } = inject('$global');
 
 const props = defineProps({
-    navId: String,
+  navId: String
 });
 
-const SYSTEM_NAME = config.defaultTitle
+const SYSTEM_NAME = config.defaultTitle;
 const slider = config.slider;
 </script>
 
-<style  lang="scss">
-.project-intro-container{
-    display: inline-block;
-    margin-top: 20px;
+<style lang="scss">
+.project-intro-container {
+  display: inline-block;
+  margin-top: 20px;
 }
 
-.project-logo{
-    transform: translateX(-12px);
+.project-logo {
+  transform: translateX(-12px);
 }
 
-.project-title-p{
-    font-size: 36px;
-    font-weight: bold;
-    color: #000;
+.project-title-p {
+  font-size: 36px;
+  font-weight: bold;
+  color: #000;
 }
 
-.project-title-highlight{
-    font-weight: bold;
-    background: linear-gradient(180deg, #41d98c, #31c4c9);
-    -webkit-background-clip: text;
-    -webkit-text-fill-color: transparent;
+.project-title-highlight {
+  font-weight: bold;
+  background: linear-gradient(180deg, #41d98c, #31c4c9);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
 }
 
-.project-slider-container{
-    display: block;
-    color: #000;
-    font-size: 15px;
-    margin: 5px 0 32px;
+.project-slider-container {
+  display: block;
+  color: #000;
+  font-size: 15px;
+  margin: 5px 0 32px;
 }
 </style>

+ 67 - 69
src/components/RecordList.vue

@@ -1,11 +1,11 @@
 <template>
-  <div :class="['record-wrap',open ? '' : 'record-wrap-close']">
+  <div :class="['record-wrap', open ? '' : 'record-wrap-close']">
     <header>
       <p>对话记录</p>
       <p @click="$emit('closeRecord')"><icon-close size="18" /></p>
     </header>
     <div class="input-wrap">
-      <a-input placeholder="搜索关键词" :style="{height:'40px',borderRadius:'4px'}">
+      <a-input placeholder="搜索关键词" :style="{ height: '40px', borderRadius: '4px' }">
         <template #prefix>
           <icon-search />
         </template>
@@ -14,18 +14,20 @@
     <div class="list-wrap">
       <div v-for="(item, index) in data" :key="index">
         <div v-if="item?.list?.length > 0">
-          <p>{{item.name}}</p>
+          <p>{{ item.name }}</p>
           <div v-for="(record, key) in item.list" :key="key" :id="`recod-item-${index}-${key}`">
-            <a-typography-paragraph :ellipsis="{rows: 1, css: true}" :style="{lineHeight: '36px',
-            padding: '0 8px',marginBottom: '0', flex: '1'}">
-              {{record}}
+            <a-typography-paragraph
+              :ellipsis="{ rows: 1, css: true }"
+              :style="{ lineHeight: '36px', padding: '0 8px', marginBottom: '0', flex: '1' }"
+            >
+              {{ record }}
             </a-typography-paragraph>
             <div class="menu">
-              <a-dropdown @select="(value) => $emit('handleSelect',value, index, key)">
+              <a-dropdown @select="(value) => $emit('handleSelect', value, index, key)">
                 <icon-more />
                 <template #content>
-                  <a-doption value="edit"><icon-edit /><span style="margin-left: 8px;">编辑</span></a-doption>
-                  <a-doption value="delete"><icon-delete /><span style="margin-left: 8px;">删除</span></a-doption>
+                  <a-doption value="edit"><icon-edit /><span style="margin-left: 8px">编辑</span></a-doption>
+                  <a-doption value="delete"><icon-delete /><span style="margin-left: 8px">删除</span></a-doption>
                 </template>
               </a-dropdown>
             </div>
@@ -38,79 +40,75 @@
 <script>
 import { defineComponent, ref } from 'vue';
 export default defineComponent({
-  components: {
-
-  },
+  components: {},
   props: ['open', 'data'],
-  setup() {
-
-  },
+  setup() {}
 });
 </script>
 <style scoped>
-  .record-wrap {
-    width: 280px;
-    height: 100%;
-    overflow: hidden;
-    transition-duration: .2s;
-    border-left: 1px solid #e5e5e5;
+.record-wrap {
+  width: 280px;
+  height: 100%;
+  overflow: hidden;
+  transition-duration: 0.2s;
+  border-left: 1px solid #e5e5e5;
+  display: flex;
+  flex-direction: column;
+  &.record-wrap-close {
+    width: 0;
+  }
+  header {
+    padding: 0 12px;
     display: flex;
-    flex-direction: column;
-    &.record-wrap-close {
-      width: 0;
+    align-items: center;
+    height: 50px;
+    border-bottom: 1px solid #e5e5e5;
+    justify-content: space-between;
+    p:nth-child(1) {
+      font-size: 16px;
+      font-weight: bold;
     }
-    header {
-      padding: 0 12px;
-      display: flex;
-      align-items: center;
-      height: 50px;
-      border-bottom: 1px solid #e5e5e5;
-      justify-content: space-between;
-      p:nth-child(1){
-        font-size: 16px;
-        font-weight: bold;
-      }
-      p:nth-child(2){
-        cursor: pointer;
-        &:hover {
-          opacity: .5;
-        }
+    p:nth-child(2) {
+      cursor: pointer;
+      &:hover {
+        opacity: 0.5;
       }
     }
-    .input-wrap {
-      margin: 16px 12px 28px;
-    }
-    .list-wrap {
-      padding: 0 12px;
-      flex: 1;
-      overflow-y: auto;
-      >div>div {
-        margin-bottom: 24px;
-        >p {
-          font-size: 12px;
-          opacity: .8;
-          margin-bottom: 8px;
+  }
+  .input-wrap {
+    margin: 16px 12px 28px;
+  }
+  .list-wrap {
+    padding: 0 12px;
+    flex: 1;
+    overflow-y: auto;
+    > div > div {
+      margin-bottom: 24px;
+      > p {
+        font-size: 12px;
+        opacity: 0.8;
+        margin-bottom: 8px;
+      }
+      > div {
+        display: flex;
+        align-items: center;
+        .menu {
+          opacity: 0;
+          cursor: pointer;
+          &:hover {
+            color: rgb(28, 97, 247);
+          }
         }
-        >div {
-          display: flex;
-          align-items: center;
+        &:hover {
+          background: rgb(245, 247, 254);
+          border-radius: 4px;
           .menu {
-            opacity: 0;
-            cursor: pointer;
-            &:hover {
-              color: rgb(28, 97, 247);
-            }
-          }
-          &:hover {
-            background: rgb(245, 247, 254);
-            border-radius: 4px;
-            .menu {
-              width: 30px;
-              opacity: 1;
-            }
+            width: 30px;
+            opacity: 1;
           }
         }
       }
     }
   }
+}
 </style>

+ 43 - 40
src/components/Slider.vue

@@ -4,8 +4,12 @@
       <img src="@/assets/slider/logo.jpg" />
     </header>
     <section class="xiaoshu-aside-left-menus-container">
-      <div v-for="(item, key) in diaplay_agents" :key="key" @click="handleClick(item.id, item.title)"
-        :class="{ active: item.id === navId }">
+      <div
+        v-for="(item, key) in diaplay_agents"
+        :key="key"
+        @click="handleClick(item.id, item.title)"
+        :class="{ active: item.id === navId }"
+      >
         <div :title="item.title" class="slide-item-container">
           <img :src="getAssetURL(`/src/assets/slider/${item.icon}.svg`)" width="24" class="img-normal" />
           <img :src="getAssetURL(`/src/assets/slider/${item.icon}-1.svg`)" width="24" class="img-hover" />
@@ -24,7 +28,7 @@
             <div style="background-color: rgb(255, 110, 110)">{{ userName?.slice(0, 1) }}</div>
             <p>{{ userName }}</p>
           </header>
-          <section class='xiaoshu-aside-left-menus-actions-container'>
+          <section class="xiaoshu-aside-left-menus-actions-container">
             <div class="item">
               <div @click="toRagflow">
                 <icon-question-circle size="large" />
@@ -236,39 +240,38 @@
 </template>
 
 <script setup>
-import { defineComponent, inject, onMounted, computed, ref, watch } from "vue";
+import { defineComponent, inject, onMounted, computed, ref, watch } from 'vue';
 import useAvailableMenus from './use-available-menus';
 
-const props = defineProps(["navId", 'agent_list']);
+const props = defineProps(['navId', 'agent_list']);
 
 const emit = defineEmits(['select-nav']);
 
 const openHelp = ref(false);
-const { ajax, helper, config } = inject("$global");
+const { ajax, helper, config } = inject('$global');
 
 const diaplay_agents = useAvailableMenus(props);
 
-const userName = ref(helper.read("userName") || "");
+const userName = ref(helper.read('userName') || '');
 if (!userName.value) {
-    helper.goLink("/login");
+  helper.goLink('/login');
 }
 const handleClick = (id, title) => {
-    emit("select-nav", { id, title });
+  emit('select-nav', { id, title });
 };
 const logout = () => {
-    helper.reset();
-    helper.goLink("/login");
+  helper.reset();
+  helper.goLink('/login');
 };
 const toRagflow = async () => {
-    const { ragflow_token } = await ajax.user.getToken();
-    if (ragflow_token) {
+  const { ragflow_token } = await ajax.user.getToken();
+  if (ragflow_token) {
     // window.open(`http://${window.location.hostname}:9222/authorization?ragflow_token=${ragflow_token}`, "_blank");
-    window.open(`http://${window.location.hostname}:11080/authorization?ragflow_token=${ragflow_token}`, "_blank");
-    }
-
-}
+    window.open(`http://${window.location.hostname}:11080/authorization?ragflow_token=${ragflow_token}`, '_blank');
+  }
+};
 
-const getAssetURL = helper.getAssetURL
+const getAssetURL = helper.getAssetURL;
 </script>
 <style lang="scss" scoped>
 main {
@@ -278,21 +281,21 @@ main {
   display: flex;
   flex-direction: column;
 
-  >header {
+  > header {
     cursor: pointer;
 
-    >img {
+    > img {
       display: block;
       width: 62px;
       margin: 0 auto;
     }
   }
 
-  >section {
+  > section {
     flex: 1;
     margin-top: 27px;
 
-    >div {
+    > div {
       margin: 0 auto;
       width: 70px;
       height: 70px;
@@ -336,13 +339,13 @@ main {
     }
   }
 
-  >footer {
+  > footer {
     margin: 0 auto 30px;
     padding: 0 10px;
     width: 80px;
     cursor: pointer;
 
-    >div {
+    > div {
       margin: 0 auto;
       width: 40px;
       height: 40px;
@@ -353,7 +356,7 @@ main {
       color: #fff;
     }
 
-    >p {
+    > p {
       margin-top: 5px;
       width: 100%;
       text-align: center;
@@ -366,11 +369,11 @@ main {
 }
 
 .user-popover {
-  >header {
+  > header {
     padding-bottom: 10px;
     border-bottom: 1px solid #e8e8e8;
 
-    >div {
+    > div {
       margin: 0 auto;
       width: 40px;
       height: 40px;
@@ -381,7 +384,7 @@ main {
       color: #fff;
     }
 
-    >p {
+    > p {
       margin-top: 5px;
       max-width: 150px;
       text-align: center;
@@ -392,7 +395,7 @@ main {
     }
   }
 
-  >section {
+  > section {
     border-bottom: 1px solid #e8e8e8;
   }
 
@@ -401,7 +404,7 @@ main {
     height: 40px;
     justify-content: center;
 
-    >div {
+    > div {
       display: flex;
       align-items: center;
       cursor: pointer;
@@ -410,22 +413,22 @@ main {
         color: #00aea3;
       }
 
-      >p {
+      > p {
         margin-left: 10px;
       }
     }
   }
 }
 
-.slide-item-container{
-    overflow: hidden;
+.slide-item-container {
+  overflow: hidden;
 }
-.title-label{
-    white-space: nowrap;
-    /* 确保文本在一行内显示 */
-    overflow: hidden;
-    /* 隐藏溢出的内容 */
-    text-overflow: ellipsis;
-    /* 使用省略号表示文本溢出 */
+.title-label {
+  white-space: nowrap;
+  /* 确保文本在一行内显示 */
+  overflow: hidden;
+  /* 隐藏溢出的内容 */
+  text-overflow: ellipsis;
+  /* 使用省略号表示文本溢出 */
 }
 </style>

+ 22 - 22
src/components/ToggleBtn.vue

@@ -1,43 +1,43 @@
 <template>
-<a-tooltip :content="text_display">
+  <a-tooltip :content="text_display">
     <span @click="openAll" class="toggle-btn">
-        <img src="@/assets/other/open.svg" width="20" v-if="closeOthers" />
-        <img src="@/assets/other/close.svg" width="20" v-else />
+      <img src="@/assets/other/open.svg" width="20" v-if="closeOthers" />
+      <img src="@/assets/other/close.svg" width="20" v-else />
     </span>
-</a-tooltip>
+  </a-tooltip>
 </template>
 
 <script setup>
-import { ref, computed } from "vue";
+import { ref, computed } from 'vue';
 
 const props = defineProps({
-    closeOthers: Boolean,
+  closeOthers: Boolean
 });
 
 const emit = defineEmits('toggle');
 
 const text_display = computed(() => {
-    return props.closeOthers ? '收起' : '展开';
+  return props.closeOthers ? '收起' : '展开';
 });
 
 const openAll = () => {
-    emit('toggle');
+  emit('toggle');
 };
 </script>
 
 <style scoped>
-.toggle-btn{
-    position: absolute;
-    bottom: -10px;
-    left: -10px;
-    z-index: 10;
-    width: 38px;
-    height: 38px;
-    border-radius: 20px;
-    background: #fff;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
+.toggle-btn {
+  position: absolute;
+  bottom: -10px;
+  left: -10px;
+  z-index: 10;
+  width: 38px;
+  height: 38px;
+  border-radius: 20px;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
 }
-</style>
+</style>

+ 28 - 30
src/components/TopBar.vue

@@ -1,30 +1,28 @@
 <template>
-<main>
-  <div v-for="(item, key) in list" :key="key" @click="chooseNav(key)">
-    <img :src="item.icon" />
-  </div>
-</main>
+  <main>
+    <div v-for="(item, key) in list" :key="key" @click="chooseNav(key)">
+      <img :src="item.icon" />
+    </div>
+  </main>
 </template>
 <script>
-import { defineComponent, ref } from 'vue'
+import { defineComponent, ref } from 'vue';
 export default defineComponent({
-  components: {
-
-  },
+  components: {},
   props: ['index'],
-  setup(props, {emit}) {
+  setup(props, { emit }) {
     const list = ref([
       {
-        icon: new URL('@/assets/icons/riLine-wechat-line.svg',import.meta.url).href,
+        icon: new URL('@/assets/icons/riLine-wechat-line.svg', import.meta.url).href,
         type: 'wechat'
       },
       {
-        icon: new URL('@/assets/icons/riLine-qr-code-line.svg',import.meta.url).href,
-        title: 'qr',
+        icon: new URL('@/assets/icons/riLine-qr-code-line.svg', import.meta.url).href,
+        title: 'qr'
       },
       {
-        icon: new URL('@/assets/icons/riLine-time-line.svg',import.meta.url).href,
-        title: 'record',
+        icon: new URL('@/assets/icons/riLine-time-line.svg', import.meta.url).href,
+        title: 'record'
       }
     ]);
     const chooseNav = (index) => {
@@ -33,25 +31,25 @@ export default defineComponent({
     return {
       list,
       chooseNav
-    }
+    };
   }
-})
+});
 </script>
 <style scoped>
-  main {
+main {
+  display: flex;
+  > div {
+    width: 24px;
+    height: 24px;
+    margin-right: 16px;
     display: flex;
-    >div {
-      width: 24px;
-      height: 24px;
-      margin-right: 16px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      cursor: pointer;
-      border-radius: 4px;
-      &:hover {
-        background: rgba(229, 229, 229, 1);
-      }
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    border-radius: 4px;
+    &:hover {
+      background: rgba(229, 229, 229, 1);
     }
   }
+}
 </style>

+ 5 - 7
src/components/answer-effect/RootImage.vue

@@ -1,5 +1,5 @@
 <template>
-    <AnwserPictureResult :image_list="image_list"/>
+  <AnwserPictureResult :image_list="image_list" />
 </template>
 
 <script setup>
@@ -7,11 +7,9 @@ import AnwserPictureResult from '../answer-pictures/AnwserPictureResult.vue';
 // import AnwserPictureLoading from './anwser-pictures/AnwserPictureLoading.vue';
 
 const props = defineProps({
-    src: String,
-    alt: String
+  src: String,
+  alt: String
 });
 
-const image_list = [
-    props.src,
-]
-</script>
+const image_list = [props.src];
+</script>

+ 16 - 10
src/components/answer-effect/RootRefference.vue

@@ -1,17 +1,23 @@
 <template>
-    <RefferenceFlag :img="img" :text="text" :doc_id="doc_id" :doc_name="doc_name" :positions="positions" :image_id="image_id"/>
+  <RefferenceFlag
+    :img="img"
+    :text="text"
+    :doc_id="doc_id"
+    :doc_name="doc_name"
+    :positions="positions"
+    :image_id="image_id"
+  />
 </template>
 
 <script setup>
-import RefferenceFlag from '../answer-refference/RefferenceFlag.vue'
+import RefferenceFlag from '../answer-refference/RefferenceFlag.vue';
 
 const props = defineProps({
-    img: String, // 图片链接
-    image_id: String,
-    text: String, // 文本地址
-    doc_id: String,
-    doc_name: String,
-    positions: Array
+  img: String, // 图片链接
+  image_id: String,
+  text: String, // 文本地址
+  doc_id: String,
+  doc_name: String,
+  positions: Array
 });
-
-</script>
+</script>

+ 46 - 46
src/components/answer-effect/apply-image-display.js

@@ -3,55 +3,55 @@ import dynamicImageDisplay from './effect-image-display';
 // const img_server = 'http://192.168.20.116';
 
 export default function applyImageDisplay(container_klass, img_list) {
-    let unmount = () => { };
+  let unmount = () => { };
 
-    // 处理回答中的图片数据
-    setTimeout(() => {
-        // 无序号,渲染所有的内容
-        const ele = document.querySelectorAll(`.${container_klass} .xiaoshuhuitu-image-container`);
+  // 处理回答中的图片数据
+  setTimeout(() => {
+    // 无序号,渲染所有的内容
+    const ele = document.querySelectorAll(`.${container_klass} .xiaoshuhuitu-image-container`);
 
-        if (ele.length === 0) {
-            return;
-        }
-
-        renderFlag(ele);
-    }, 0);
-
-    function renderFlag(ele) {
-        // 遍历找到的所有标记元素
-        ele.forEach((item, idx) => {
-            let data_src = '';
-            if (img_list && Array.isArray(img_list)) {
-                const img_src = img_list[idx];
-
-                if (img_src) {
-                    // 合法的src
-                    // data_src = `${img_server}${img_src}`
-                    data_src = `/api/files/image/${img_src}`;
-                    // data_src = item.getAttribute('data-src');
-                } else {
-                    // 非法的src
-                    data_src = item.getAttribute('data-src');
-                }
-            } else {
-                // 无
-                data_src = item.getAttribute('data-src');
-            }
-
-            // const data_src = item.getAttribute('data-src');
-
-            const data_alt = item.getAttribute('data-alt');
-
-            unmount = dynamicImageDisplay(item, {
-                src: data_src,
-                alt: data_alt
-            });
-        });
+    if (ele.length === 0) {
+      return;
     }
 
-    return () => {
-        if (typeof unmount === 'function') {
-            unmount();
+    renderFlag(ele);
+  }, 0);
+
+  function renderFlag(ele) {
+    // 遍历找到的所有标记元素
+    ele.forEach((item, idx) => {
+      let data_src = '';
+      if (img_list && Array.isArray(img_list)) {
+        const img_src = img_list[idx];
+
+        if (img_src) {
+          // 合法的src
+          // data_src = `${img_server}${img_src}`
+          data_src = `/api/files/image/${img_src}`;
+          // data_src = item.getAttribute('data-src');
+        } else {
+          // 非法的src
+          data_src = item.getAttribute('data-src');
         }
+      } else {
+        // 无
+        data_src = item.getAttribute('data-src');
+      }
+
+      // const data_src = item.getAttribute('data-src');
+
+      const data_alt = item.getAttribute('data-alt');
+
+      unmount = dynamicImageDisplay(item, {
+        src: data_src,
+        alt: data_alt
+      });
+    });
+  }
+
+  return () => {
+    if (typeof unmount === 'function') {
+      unmount();
     }
-}
+  }
+}

+ 50 - 50
src/components/answer-effect/apply-refference-popover.js

@@ -2,60 +2,60 @@ import dynamicRegRefFlag from './effect-refference-flag'
 
 /**
  * 应用PDF文档引用
- * @param {string} container_klass 
+ * @param {string} container_klass
  * @param {object} refference - 引用数据
- * @returns 
+ * @returns
  */
 export default function applyRefferencePopover(container_klass, refference) {
-    let unmount = () => { };
-
-    // 处理引用数据
-    setTimeout(() => {
-        // 无序号,渲染所有的内容
-        const ele = document.querySelectorAll(`.${container_klass} .refflag-refflag-refflag`);
-
-        renderFlag(ele);
-    }, 0);
-
-    function renderFlag(ele) {
-        // 遍历找到的所有标记元素
-        ele.forEach((item, idx) => {
-            const data_flag_index = item.getAttribute('data-flag-index');
-            const data_list_index = item.getAttribute('data-list-index');
-
-            if (refference) {
-                const chunks = refference.chunks;
-
-                if (chunks) {
-                    const target_chunk = chunks[data_flag_index];
-
-                    // 引用数据
-                    const current_refference_obj = {
-                        refference: {
-                            chunk_id: target_chunk.chunk_id,
-                            content_ltks: target_chunk.content_ltks,
-                            content_with_weight: target_chunk.content_with_weight,
-                            doc_id: target_chunk.doc_id,
-                            docnm_kwd: target_chunk.docnm_kwd,
-                            img_id: target_chunk.img_id,
-                            important_kwd: target_chunk.important_kwd,
-                            kb_id: target_chunk.kb_id,
-                            positions: target_chunk.positions,
-                            similarity: target_chunk.similarity,
-                            term_similarity: target_chunk.term_similarity,
-                            vector_similarity: target_chunk.vector_similarity,
-                        }
-                    }
-
-                    unmount = dynamicRegRefFlag(item, current_refference_obj);
-                }
+  let unmount = () => { };
+
+  // 处理引用数据
+  setTimeout(() => {
+    // 无序号,渲染所有的内容
+    const ele = document.querySelectorAll(`.${container_klass} .refflag-refflag-refflag`);
+
+    renderFlag(ele);
+  }, 0);
+
+  function renderFlag(ele) {
+    // 遍历找到的所有标记元素
+    ele.forEach((item, idx) => {
+      const data_flag_index = item.getAttribute('data-flag-index');
+      const data_list_index = item.getAttribute('data-list-index');
+
+      if (refference) {
+        const chunks = refference.chunks;
+
+        if (chunks) {
+          const target_chunk = chunks[data_flag_index];
+
+          // 引用数据
+          const current_refference_obj = {
+            refference: {
+              chunk_id: target_chunk.chunk_id,
+              content_ltks: target_chunk.content_ltks,
+              content_with_weight: target_chunk.content_with_weight,
+              doc_id: target_chunk.doc_id,
+              docnm_kwd: target_chunk.docnm_kwd,
+              img_id: target_chunk.img_id,
+              important_kwd: target_chunk.important_kwd,
+              kb_id: target_chunk.kb_id,
+              positions: target_chunk.positions,
+              similarity: target_chunk.similarity,
+              term_similarity: target_chunk.term_similarity,
+              vector_similarity: target_chunk.vector_similarity,
             }
-        });
-    }
+          }
 
-    return () => {
-        if (typeof unmount === 'function') {
-            unmount();
+          unmount = dynamicRegRefFlag(item, current_refference_obj);
         }
+      }
+    });
+  }
+
+  return () => {
+    if (typeof unmount === 'function') {
+      unmount();
     }
-}
+  }
+}

+ 19 - 19
src/components/answer-effect/effect-image-display.js

@@ -8,29 +8,29 @@ import RootImage from './RootImage.vue';
 /**
  * 动态展示生成的图片
  * @param {Element} mount_element - 挂载点元素
- * @param {Object} propsObject - props值 
+ * @param {Object} propsObject - props值
  * @param {string} propsObject.src - 图片链接
  * @param {string} propsObject.alt - alt值
  */
 export default function dynamicImageDisplay(mount_element, propsObject = {}) {
-    /**
-     * @see https://cn.vuejs.org/api/application.html#createapp
-     */
-    const app = createApp(RootImage, {
-        src: propsObject.src,
-        alt: propsObject.alt
-    });
-
-    // 引用字节跳动相关的组件
-    app.use(ArcoVueIcon);
-    app.use(ArcoVue);
-
-    app.mount(mount_element);
-
-    // 返回一个卸载APP的方法
-    return () => {
-        app.unmount();
-    }
+  /**
+   * @see https://cn.vuejs.org/api/application.html#createapp
+   */
+  const app = createApp(RootImage, {
+    src: propsObject.src,
+    alt: propsObject.alt
+  });
+
+  // 引用字节跳动相关的组件
+  app.use(ArcoVueIcon);
+  app.use(ArcoVue);
+
+  app.mount(mount_element);
+
+  // 返回一个卸载APP的方法
+  return () => {
+    app.unmount();
+  }
 }
 
 

+ 23 - 23
src/components/answer-effect/effect-refference-flag.js

@@ -8,7 +8,7 @@ import RootRefference from './RootRefference.vue';
 /**
  * 创建一个vue APP,并将此APP挂载到对应的DOM节点中
  * @param {Element} mount_element - 挂载点元素
- * @param {Object} propsObject - props值 
+ * @param {Object} propsObject - props值
  * @param {string} propsObject.refference.chunk_id - 目标ID
  * @param {string} propsObject.refference.content_ltks - 主要内容
  * @param {string} propsObject.refference.content_with_weight - 重点描述文本
@@ -23,28 +23,28 @@ import RootRefference from './RootRefference.vue';
  * @param {string} propsObject.refference.vector_similarity - 目标ID
  */
 export default function dynamicRegRefFlag(mount_element, propsObject = {}) {
-    /**
-     * @see https://cn.vuejs.org/api/application.html#createapp
-     */
-    const app = createApp(RootRefference, {
-        img: propsObject.refference.img_id || '',
-        image_id: propsObject.refference.img_id,
-        text: propsObject.refference.content_with_weight || '',
-        doc_id: propsObject.refference.doc_id,
-        doc_name: propsObject.refference.docnm_kwd,
-        positions: propsObject.refference.positions,
-    });
-
-    // 引用字节跳动相关的组件
-    app.use(ArcoVueIcon);
-    app.use(ArcoVue);
-
-    app.mount(mount_element);
-
-    // 返回一个卸载APP的方法
-    return () => {
-        app.unmount();
-    }
+  /**
+   * @see https://cn.vuejs.org/api/application.html#createapp
+   */
+  const app = createApp(RootRefference, {
+    img: propsObject.refference.img_id || '',
+    image_id: propsObject.refference.img_id,
+    text: propsObject.refference.content_with_weight || '',
+    doc_id: propsObject.refference.doc_id,
+    doc_name: propsObject.refference.docnm_kwd,
+    positions: propsObject.refference.positions,
+  });
+
+  // 引用字节跳动相关的组件
+  app.use(ArcoVueIcon);
+  app.use(ArcoVue);
+
+  app.mount(mount_element);
+
+  // 返回一个卸载APP的方法
+  return () => {
+    app.unmount();
+  }
 }
 
 

+ 57 - 57
src/components/answer-effect/format-anwser-string.js

@@ -8,74 +8,74 @@ export const REFFERENCE_FLAG = 'refference-flag';
 
 /**
  * 转换AI的anwser数据
- * @param {string} string - 待转换数据 
- * @returns 
+ * @param {string} string - 待转换数据
+ * @returns
  */
 export default function formatAnwserString(string) {
-    if (!string) {
-        return '';
-    }
+  if (!string) {
+    return '';
+  }
 
-    /**
-     * 临时替换 []( 为 ![](
-     * 因为后端目前返回的图片格式非图片格式 而是 连接格式
-     * 待数据返回正确后,此处代码再做调整
-     */
-    let temp_str = string;
-    if (string.indexOf('![]') < 0) {
-        // // 未发现 ![] 字符串,尝试将 [] 替换为 ![]
-        // temp_str = string.replace(/\[\]\(/g, '![](');
-    } else {
-        // 已发现 ![] 字符串
-    }
+  /**
+   * 临时替换 []( 为 ![](
+   * 因为后端目前返回的图片格式非图片格式 而是 连接格式
+   * 待数据返回正确后,此处代码再做调整
+   */
+  let temp_str = string;
+  if (string.indexOf('![]') < 0) {
+    // // 未发现 ![] 字符串,尝试将 [] 替换为 ![]
+    // temp_str = string.replace(/\[\]\(/g, '![](');
+  } else {
+    // 已发现 ![] 字符串
+  }
 
-    const result = marked.parse(temp_str);
+  const result = marked.parse(temp_str);
 
-    /**
-     * 将链接替换为新窗口打开
-     */
-    let parse_href = result.replace('<a href=', '<a target="_blank" href=');
+  /**
+   * 将链接替换为新窗口打开
+   */
+  let parse_href = result.replace('<a href=', '<a target="_blank" href=');
 
-    /**
-     * 替换图片字符串
-     * 将字符串中的图片数据替换掉
-     */
-    var rep_img = parse_href.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function (match, str) {
-        // match值类似于
-        //         <img src="https://res.stepfun.com/image_gen/20241125/01936254e2ad7aea9d3d371d9a376469.png?X-Tos-Algorithm=TOS4-HMAC-SHA256&X-Tos-Credential=AKLTYTJhYzZiM2JhZTU2N
-        // GMxMGFkNTkwNTk3OTVkJDQ%2F20241125%2Fcn-shanghai%2Ftos%2Frequest&X-Tos-Date=20241125T075910Z&X-Tos-Expires=3600&x-Tos-Signature=3fa70bdbcc1759ab45aaa1b8bd60eef886e55114c32a39f478ee85d4f262804e&x-Tos-SignededH
-        // eaders=host" alt="">
+  /**
+   * 替换图片字符串
+   * 将字符串中的图片数据替换掉
+   */
+  var rep_img = parse_href.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/gi, function (match, str) {
+    // match值类似于
+    //         <img src="https://res.stepfun.com/image_gen/20241125/01936254e2ad7aea9d3d371d9a376469.png?X-Tos-Algorithm=TOS4-HMAC-SHA256&X-Tos-Credential=AKLTYTJhYzZiM2JhZTU2N
+    // GMxMGFkNTkwNTk3OTVkJDQ%2F20241125%2Fcn-shanghai%2Ftos%2Frequest&X-Tos-Date=20241125T075910Z&X-Tos-Expires=3600&x-Tos-Signature=3fa70bdbcc1759ab45aaa1b8bd60eef886e55114c32a39f478ee85d4f262804e&x-Tos-SignededH
+    // eaders=host" alt="">
 
-        const box = document.createElement('div');
-        box.innerHTML = match;
-        const image_ele = box.querySelector('img');
-        const img_src = image_ele.src; // 图片链接
-        // const img_src = 'http://localhost/src/assets/slider/logo.jpg';
-        const img_alt = image_ele.alt; // 图片alt属性
+    const box = document.createElement('div');
+    box.innerHTML = match;
+    const image_ele = box.querySelector('img');
+    const img_src = image_ele.src; // 图片链接
+    // const img_src = 'http://localhost/src/assets/slider/logo.jpg';
+    const img_alt = image_ele.alt; // 图片alt属性
 
-        return `<span class="xiaoshuhuitu-image-container" data-src="${img_src}" data-alt="${img_alt}"></span>`;
-    });
+    return `<span class="xiaoshuhuitu-image-container" data-src="${img_src}" data-alt="${img_alt}"></span>`;
+  });
 
-    /**
-     * 文档引用效果
-     */
-    const reg = /<span class="circle" data-list-index="\d"><\/span>/g;
+  /**
+   * 文档引用效果
+   */
+  const reg = /<span class="circle" data-list-index="\d"><\/span>/g;
 
-    /**
-     * 处理回答的每一个答案中
-     * 关于引用的标记标签
-     * 在界面中可以通过 refference-flag 获取到对应的元素
-     */
-    let idx = 0; // 记录当前是第几次匹配
-    const formated = rep_img.replaceAll(reg, function (match, index, full_str, c) {
-        let match_final = match.replace('></span>', `data-flag-index="${idx}"></span>`);
+  /**
+   * 处理回答的每一个答案中
+   * 关于引用的标记标签
+   * 在界面中可以通过 refference-flag 获取到对应的元素
+   */
+  let idx = 0; // 记录当前是第几次匹配
+  const formated = rep_img.replaceAll(reg, function (match, index, full_str, c) {
+    let match_final = match.replace('></span>', `data-flag-index="${idx}"></span>`);
 
-        match_final = match_final.replace('class="circle"', `class="refflag-refflag-refflag ${REFFERENCE_FLAG}"`);
+    match_final = match_final.replace('class="circle"', `class="refflag-refflag-refflag ${REFFERENCE_FLAG}"`);
 
-        idx++;
+    idx++;
 
-        return match_final;
-    });
+    return match_final;
+  });
 
-    return formated;
-};
+  return formated;
+};

+ 9 - 9
src/components/answer-effect/marked-lib.js

@@ -22,14 +22,14 @@ import { Marked } from "marked";
 // const { Marked } = globalThis.marked;
 // const { markedHighlight } = globalThis.markedHighlight;
 const marked = new Marked(
-    // markedHighlight({
-    //     emptyLangClass: 'hljs',
-    //     langPrefix: 'hljs language-',
-    //     highlight(code, lang, info) {
-    //         const language = hljs.getLanguage(lang) ? lang : 'plaintext';
-    //         return hljs.highlight(code, { language }).value;
-    //     }
-    // })
+  // markedHighlight({
+  //     emptyLangClass: 'hljs',
+  //     langPrefix: 'hljs language-',
+  //     highlight(code, lang, info) {
+  //         const language = hljs.getLanguage(lang) ? lang : 'plaintext';
+  //         return hljs.highlight(code, { language }).value;
+  //     }
+  // })
 );
 
 export default marked;
@@ -40,4 +40,4 @@ export default marked;
 //         // then highlight each
 //         hljs.highlightElement(el);
 //     });
-// }
+// }

+ 59 - 59
src/components/answer-effect/temp-history.js

@@ -1,82 +1,82 @@
 /**
  * 从socket连接地址中获取到聊天记录值
- * @param {string} socket_url 
- * @returns 
+ * @param {string} socket_url
+ * @returns
  */
 export function getChatIdFromUrl(socket_url) {
-    /**
-     * 例如:ws://localhost/api/chat/ws/42e4fcdc9bea11efac300242ac160006/765f672c700f49b79a473fc906fe388c?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwidXNlcl9pZCI6MjEsImV4cCI6MTczMjQzNzkzNH0.7SPOZpnaTUu2KPzWIJrhhkRehjePeuL8TABo7rNgnCY
-     */
-    // const socket_url = event.target.url; // socket连接地址
-    const url_parts = socket_url.split('?'); // 使用 ? 进行切分
-    const url_core_parts = url_parts[0].split('/'); // 将前面部分继续使用 / 进行切分
-    const chat_id = url_core_parts[url_core_parts.length - 1]; // 获取到聊天ID
+  /**
+   * 例如:ws://localhost/api/chat/ws/42e4fcdc9bea11efac300242ac160006/765f672c700f49b79a473fc906fe388c?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwidXNlcl9pZCI6MjEsImV4cCI6MTczMjQzNzkzNH0.7SPOZpnaTUu2KPzWIJrhhkRehjePeuL8TABo7rNgnCY
+   */
+  // const socket_url = event.target.url; // socket连接地址
+  const url_parts = socket_url.split('?'); // 使用 ? 进行切分
+  const url_core_parts = url_parts[0].split('/'); // 将前面部分继续使用 / 进行切分
+  const chat_id = url_core_parts[url_core_parts.length - 1]; // 获取到聊天ID
 
-    return chat_id;
+  return chat_id;
 }
 
 /**
  * 初始化一个临时历史记录
  */
 export default function initTempHistory() {
-    let temp_history_map = {};
-    let temp_history_list = []; // 临时保存聊天历史记录
-
-    /**
-     * 处理临时历史记录数据
-     * @param {SocketEvent} event 
-     * @returns 
-     */
-    const setTempHistory = (event) => {
-        let res_data = null;
-
-        try {
-            res_data = JSON.parse(event.data);
-        } catch (err) {
-            console.log(err);
-        }
-
-        if (!res_data) {
-            return;
-        }
-
-        /**
-         * 例如:ws://localhost/api/chat/ws/42e4fcdc9bea11efac300242ac160006/765f672c700f49b79a473fc906fe388c?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwidXNlcl9pZCI6MjEsImV4cCI6MTczMjQzNzkzNH0.7SPOZpnaTUu2KPzWIJrhhkRehjePeuL8TABo7rNgnCY
-         */
-        const socket_url = event.target.url; // socket连接地址
+  let temp_history_map = {};
+  let temp_history_list = []; // 临时保存聊天历史记录
 
-        const chat_id = getChatIdFromUrl(socket_url);
+  /**
+   * 处理临时历史记录数据
+   * @param {SocketEvent} event
+   * @returns
+   */
+  const setTempHistory = (event) => {
+    let res_data = null;
 
-        if (temp_history_list.indexOf(chat_id) < 0) {
-            // 还未保存记录
-            temp_history_list.push(chat_id);
-        } else {
-            // 已经保存,则无需再保存
-        }
+    try {
+      res_data = JSON.parse(event.data);
+    } catch (err) {
+      console.log(err);
+    }
 
-        temp_history_map[chat_id] = res_data;
+    if (!res_data) {
+      return;
     }
+
     /**
-     * 获取临时历史记录
+     * 例如:ws://localhost/api/chat/ws/42e4fcdc9bea11efac300242ac160006/765f672c700f49b79a473fc906fe388c?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwidXNlcl9pZCI6MjEsImV4cCI6MTczMjQzNzkzNH0.7SPOZpnaTUu2KPzWIJrhhkRehjePeuL8TABo7rNgnCY
      */
-    const getTempHistory = () => {
-        const arr = [];
-        temp_history_list.forEach(item => {
-            const data = temp_history_map[item];
+    const socket_url = event.target.url; // socket连接地址
 
-            arr.push(data);
-        });
+    const chat_id = getChatIdFromUrl(socket_url);
 
-        return arr;
+    if (temp_history_list.indexOf(chat_id) < 0) {
+      // 还未保存记录
+      temp_history_list.push(chat_id);
+    } else {
+      // 已经保存,则无需再保存
     }
 
-    const getCurIndex = (chat_id) => {
-        return temp_history_list.indexOf(chat_id);
-    }
+    temp_history_map[chat_id] = res_data;
+  }
+  /**
+   * 获取临时历史记录
+   */
+  const getTempHistory = () => {
+    const arr = [];
+    temp_history_list.forEach(item => {
+      const data = temp_history_map[item];
 
-    return {
-        setHistory: setTempHistory,
-        getHistory: getTempHistory,
-        getChatIndex: getCurIndex,
-    }
+      arr.push(data);
+    });
+
+    return arr;
+  }
+
+  const getCurIndex = (chat_id) => {
+    return temp_history_list.indexOf(chat_id);
+  }
+
+  return {
+    setHistory: setTempHistory,
+    getHistory: getTempHistory,
+    getChatIndex: getCurIndex,
+  }
 }

+ 3 - 3
src/components/answer-effect/test.marked.js

@@ -4,9 +4,9 @@ import { marked } from "marked";
 var str = "```import matplotlib.pyplot as plt\nfrom matplotlib.font_manager import FontProperties\n\n# 设置字体以支持中文显示\nfont_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc'\nfont = FontProperties(fname = font_path) \n\n# 数据\nlocations = ['东营市', '临沂市', '威海市', '德州市', '日照市', '枣庄市', '泰安市', '济南市', '济宁市', '淄博市', '滨州市', '潍坊市', '烟台市', '聊城市', '莱芜市', '菏泽市', '青岛市']\nuniversities_count = [2, 3, 3, 2, 2, 3, 6, 31, 5, 7, 3, 10, 8, 2, 1, 4, 10]\n\n# 绘制饼状图\nplt.figure(figsize = (10, 8)) \nplt.pie(universities_count, labels = locations, autopct = '%1.1f%%', startangle = 140, textprops = { 'fontproperties': font }) \nplt.title('山东省各市高校数量分布', fontproperties = font) \nplt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.\n\n# 保存图片\nsave_path = './downloads/images/f64fc613bc9f4264abcbaebe169dbea1_1732788687.jpg'\nplt.savefig(save_path, dpi = 300, bbox_inches = 'tight') \n\nplt.show()```"
 
 function test() {
-    const result = marked.parse(str);
+  const result = marked.parse(str);
 
-    console.log(result);
+  console.log(result);
 }
 
-test();
+test();

+ 66 - 65
src/components/answer-pictures/AnwserInfo.vue

@@ -1,108 +1,109 @@
 <template>
-    <div class="anwser-pictures-info">
-        <div class="anwser-pictures-index-container">
-            <span class="pic-arrow-btn pre" @click="handlePre">
-                <img :src="left_normal_icon" v-if="!can_go_pre"/>
-                <img :src="left_hover_icon" v-if="can_go_pre"/>
-            </span>
-
-            <span><span class="current-index">{{current}}</span> / {{total}}</span>
-
-            <span class="pic-arrow-btn next" @click="handleNext">
-                <img :src="right_hover_icon" v-if="can_go_next"/>
-                <img :src="right_normal_icon" v-if="!can_go_next"/>
-            </span>
-
-            <span>回答已停止生成</span>
-        </div>
+  <div class="anwser-pictures-info">
+    <div class="anwser-pictures-index-container">
+      <span class="pic-arrow-btn pre" @click="handlePre">
+        <img :src="left_normal_icon" v-if="!can_go_pre" />
+        <img :src="left_hover_icon" v-if="can_go_pre" />
+      </span>
+
+      <span
+        ><span class="current-index">{{ current }}</span> / {{ total }}</span
+      >
+
+      <span class="pic-arrow-btn next" @click="handleNext">
+        <img :src="right_hover_icon" v-if="can_go_next" />
+        <img :src="right_normal_icon" v-if="!can_go_next" />
+      </span>
+
+      <span>回答已停止生成</span>
     </div>
+  </div>
 </template>
 
 <script setup>
-import {ref, computed} from 'vue';
+import { ref, computed } from 'vue';
 
-import left_hover_icon from '../../assets/images/left-hover.svg'
-import left_normal_icon from '../../assets/images/left-normal.svg'
-import right_hover_icon from '../../assets/images/right-hover.svg'
-import right_normal_icon from '../../assets/images/right-normal.svg'
+import left_hover_icon from '../../assets/images/left-hover.svg';
+import left_normal_icon from '../../assets/images/left-normal.svg';
+import right_hover_icon from '../../assets/images/right-hover.svg';
+import right_normal_icon from '../../assets/images/right-normal.svg';
 
 const props = defineProps({
-    current: Number, // 当前的序号
-    total: Number, // 回答的总数
+  current: Number, // 当前的序号
+  total: Number // 回答的总数
 });
 
 const emit = defineEmits('pre', 'next');
 
 const can_go_pre = computed(() => {
-    const pre_index = props.current - 1;
+  const pre_index = props.current - 1;
 
-    return pre_index >= 1;
+  return pre_index >= 1;
 });
 const can_go_next = computed(() => {
-    const next_index = props.current + 1;
+  const next_index = props.current + 1;
 
-    return next_index <= props.total;
+  return next_index <= props.total;
 });
 
 /**
  * 前一张图片
  */
 const handlePre = () => {
-    const pre_index = props.current - 1;
-
-    if(pre_index < 1){
-        // 已经是第0张,前面没有了
-        return;
-    }else{
-        emit('pre', pre_index);
-    }
-}
+  const pre_index = props.current - 1;
+
+  if (pre_index < 1) {
+    // 已经是第0张,前面没有了
+    return;
+  } else {
+    emit('pre', pre_index);
+  }
+};
 
 /**
  * 后一张图片
  */
 const handleNext = () => {
-    const next_index = props.current + 1;
-
-    if(next_index > props.total){
-        console.log('已经是最后一张了');
-        return;
-    }else{
-        emit('next', next_index);
-    }
-}
+  const next_index = props.current + 1;
+
+  if (next_index > props.total) {
+    console.log('已经是最后一张了');
+    return;
+  } else {
+    emit('next', next_index);
+  }
+};
 </script>
 
 <style scoped>
-.anwser-pictures-container{
-
+.anwser-pictures-container {
 }
 
-.anwser-pictures-images{
-    width: 450px;
-    height: 450px;
-    border-radius: 15px;
-    overflow: hidden;
+.anwser-pictures-images {
+  width: 450px;
+  height: 450px;
+  border-radius: 15px;
+  overflow: hidden;
 }
 
-.anwser-pictures-index-container{
-    display: flex;
-    align-items: center;
+.anwser-pictures-index-container {
+  display: flex;
+  align-items: center;
 }
 
-.pic-arrow-btn{
-    cursor: pointer;
-    display: flex;
-    justify-content: center;
-    align-items: center;
+.pic-arrow-btn {
+  cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
-.current-index{
-    font-weight: bold;
+.current-index {
+  font-weight: bold;
 }
 
-.anwser-pictures-info{
-    /* margin-top: 15px; */
-    font-size: 16px;
+.anwser-pictures-info {
+  /* margin-top: 15px; */
+  font-size: 16px;
 }
 </style>

+ 9 - 10
src/components/answer-pictures/AnwserPictureLoading.vue

@@ -1,20 +1,19 @@
 <template>
-    <div class="anwser-pictures-loading">
-        <img :src="image_loading" />
-    </div>
+  <div class="anwser-pictures-loading">
+    <img :src="image_loading" />
+  </div>
 </template>
 <script setup>
-import image_loading from '../../assets/images/loading.gif'
-
+import image_loading from '../../assets/images/loading.gif';
 </script>
 
 <style scoped>
-.anwser-pictures-loading{
-    width: 35px;
-    height: 35px;
+.anwser-pictures-loading {
+  width: 35px;
+  height: 35px;
 }
 
-.anwser-pictures-loading img{
-    width: 100%;
+.anwser-pictures-loading img {
+  width: 100%;
 }
 </style>

+ 70 - 80
src/components/answer-pictures/AnwserPictureResult.vue

@@ -1,122 +1,112 @@
 <template>
-    <div class="anwser-pictures-container">
-        <div class="anwser-pictures-images">
-            <a-carousel
-                :style="{
-                    width: '450px',
-                    height: '450px',
-                    borderRadius: '15px'
-                }"
-                :auto-play="false"
-                :current="cur_index"
-                animation-name="fade"
-                show-arrow="never"
-                indicator-type="never"
-            >
-                <a-carousel-item v-for="image in image_list" :key="image">
-                    <a-image
-                        data-flag="a-image-container"
-                        :src="image"
-                        :style="{
-                            width: '100%',
-                        }"
-                        :hide-footer="true"
-                        show-loader
-                    />
-                </a-carousel-item>
-            </a-carousel>
-        </div>
-
-        <div class="anwser-info-container-with-edit">
-            <AnwserInfo  
-                v-if="!is_only_one" 
-                :current="cur_index" 
-                :total="image_total" 
-                @pre="handlePre" 
-                @next="handleNext" 
-            />
-
-            <ImgEditBtn :image_url="image_list[cur_index - 1]"/>
-        </div>
+  <div class="anwser-pictures-container">
+    <div class="anwser-pictures-images">
+      <a-carousel
+        :style="{
+          width: '450px',
+          height: '450px',
+          borderRadius: '15px'
+        }"
+        :auto-play="false"
+        :current="cur_index"
+        animation-name="fade"
+        show-arrow="never"
+        indicator-type="never"
+      >
+        <a-carousel-item v-for="image in image_list" :key="image">
+          <a-image
+            data-flag="a-image-container"
+            :src="image"
+            :style="{
+              width: '100%'
+            }"
+            :hide-footer="true"
+            show-loader
+          />
+        </a-carousel-item>
+      </a-carousel>
     </div>
+
+    <div class="anwser-info-container-with-edit">
+      <AnwserInfo v-if="!is_only_one" :current="cur_index" :total="image_total" @pre="handlePre" @next="handleNext" />
+
+      <ImgEditBtn :image_url="image_list[cur_index - 1]" />
+    </div>
+  </div>
 </template>
 <script setup>
-import {ref, computed} from 'vue';
+import { ref, computed } from 'vue';
 
 import AnwserInfo from './AnwserInfo.vue';
 
-import left_hover_icon from '../../assets/images/left-hover.svg'
-import left_normal_icon from '../../assets/images/left-normal.svg'
-import right_hover_icon from '../../assets/images/right-hover.svg'
-import right_normal_icon from '../../assets/images/right-normal.svg'
+import left_hover_icon from '../../assets/images/left-hover.svg';
+import left_normal_icon from '../../assets/images/left-normal.svg';
+import right_hover_icon from '../../assets/images/right-hover.svg';
+import right_normal_icon from '../../assets/images/right-normal.svg';
 
 import ImgEditBtn from '../image-editor/ImgEditBtn.vue';
 
-
 const cur_index = ref(1);
 
 const props = defineProps({
-    image_list: Array
+  image_list: Array
 });
 
-const image_total = props.image_list && props.image_list.length || 0;
+const image_total = (props.image_list && props.image_list.length) || 0;
 
 // 是否只有一张图片
 const is_only_one = computed(() => {
-    return image_total === 0;
+  return image_total === 0;
 });
 
 /**
  * 前一张图片
  */
 const handlePre = () => {
-    const pre_index = cur_index.value - 1;
-
-    if(pre_index < 1){
-        // 已经是第0张,前面没有了
-        return;
-    }else{
-        cur_index.value = pre_index;
-    }
-}
+  const pre_index = cur_index.value - 1;
+
+  if (pre_index < 1) {
+    // 已经是第0张,前面没有了
+    return;
+  } else {
+    cur_index.value = pre_index;
+  }
+};
 
 /**
  * 后一张图片
  */
 const handleNext = () => {
-    const next_index = cur_index.value + 1;
-
-    if(next_index > image_total){
-        return;
-    }else{
-        cur_index.value = next_index;
-    }
-}
+  const next_index = cur_index.value + 1;
+
+  if (next_index > image_total) {
+    return;
+  } else {
+    cur_index.value = next_index;
+  }
+};
 </script>
 
 <style scoped>
-.anwser-pictures-container{
-
+.anwser-pictures-container {
 }
 
-.anwser-pictures-images{
-    width: 450px;
-    height: 450px;
-    border-radius: 15px;
-    overflow: hidden;
+.anwser-pictures-images {
+  width: 450px;
+  height: 450px;
+  border-radius: 15px;
+  overflow: hidden;
 }
 
-.anwser-info-container-with-edit{
-    margin-top: 15px;
-    display: flex;
-    align-items: center;
+.anwser-info-container-with-edit {
+  margin-top: 15px;
+  display: flex;
+  align-items: center;
 }
-
-
 </style>
 
 <style>
-.anwser-pictures-images img{
-    width: 100%;
+.anwser-pictures-images img {
+  width: 100%;
 }
 </style>

+ 23 - 24
src/components/answer-refference/AsideImage.vue

@@ -1,40 +1,39 @@
 <template>
-    <a-popover>
-        <div class="image-aisde-btn-container">
-            <img :src="src" class="image-aside-btn" />
-        </div>
-        
-        <template #content>
-            <img :src="src" class="image-large-view" />
-        </template>
-    </a-popover>
+  <a-popover>
+    <div class="image-aisde-btn-container">
+      <img :src="src" class="image-aside-btn" />
+    </div>
+
+    <template #content>
+      <img :src="src" class="image-large-view" />
+    </template>
+  </a-popover>
 </template>
 <script setup>
-import {ref, computed} from 'vue';
+import { ref, computed } from 'vue';
 
 const props = defineProps({
-    src: String
+  src: String
 });
 </script>
 
 <style scoped>
-.image-aisde-btn-container{
-    width: 120px;
-    max-height: 120px;
-    flex-shrink: 0;
-    overflow: hidden;
+.image-aisde-btn-container {
+  width: 120px;
+  max-height: 120px;
+  flex-shrink: 0;
+  overflow: hidden;
 
-    margin-right: 5px;
+  margin-right: 5px;
 }
 
-.image-aside-btn{
-    width: 120px;
-    max-height: 120px;
-
+.image-aside-btn {
+  width: 120px;
+  max-height: 120px;
 }
 
-.image-large-view{
-    max-width: 540px;
-    max-height: 540px;
+.image-large-view {
+  max-width: 540px;
+  max-height: 540px;
 }
 </style>

+ 66 - 59
src/components/answer-refference/RefferenceFlag.vue

@@ -1,43 +1,51 @@
 <template>
-    <span class="refference-container">
-        <a-popover>
-            <span class="circle"></span>
-
-            <template #title></template>
-            <template #content>
-                <div class="refference-content">
-                    <AsideImage :src="img_url"/>
-
-                    <div class="refference-description">
-                        <div class="ref-text-content">
-                            {{text}}
-                        </div>
-
-                        <FileNameDisplay @click="handleClick" :file_name="doc_name" :file_id="doc_id" />
-                    </div>
-                </div>
-                
-            </template>
-        </a-popover>
-
-        <a-drawer ref="drawer" :width="DOC_WIDTH" :visible="visible" @ok="handleOk" @cancel="handleCancel" unmountOnClose :data-flag="'doc-ref-effect-contaienr'" :footer="false">
-            <template #title>
-                {{doc_name}}
-            </template>
-
-            <PDFViewer :url="pdf_url" :doc_width="DOC_WIDTH" :positions="positions"/>
-        </a-drawer>
-    </span>
+  <span class="refference-container">
+    <a-popover>
+      <span class="circle"></span>
+
+      <template #title></template>
+      <template #content>
+        <div class="refference-content">
+          <AsideImage :src="img_url" />
+
+          <div class="refference-description">
+            <div class="ref-text-content">
+              {{ text }}
+            </div>
+
+            <FileNameDisplay @click="handleClick" :file_name="doc_name" :file_id="doc_id" />
+          </div>
+        </div>
+      </template>
+    </a-popover>
+
+    <a-drawer
+      ref="drawer"
+      :width="DOC_WIDTH"
+      :visible="visible"
+      @ok="handleOk"
+      @cancel="handleCancel"
+      unmountOnClose
+      :data-flag="'doc-ref-effect-contaienr'"
+      :footer="false"
+    >
+      <template #title>
+        {{ doc_name }}
+      </template>
+
+      <PDFViewer :url="pdf_url" :doc_width="DOC_WIDTH" :positions="positions" />
+    </a-drawer>
+  </span>
 </template>
 <script setup>
-import { defineComponent, inject, ref, useTemplateRef } from "vue";
+import { defineComponent, inject, ref, useTemplateRef } from 'vue';
 
 import PDFViewer from '../pdf-viewer/PDFViewer.vue';
 
 import AsideImage from './AsideImage.vue';
 import FileNameDisplay from '../file/FileNameDisplay.vue';
 
-import {getDocumentUrl, getImageUrl} from '../../ajax/document';
+import { getDocumentUrl, getImageUrl } from '../../ajax/document';
 
 /**
  * 此页面可能用到的文档
@@ -45,15 +53,15 @@ import {getDocumentUrl, getImageUrl} from '../../ajax/document';
  */
 
 const props = defineProps({
-    img: String, // 图片链接
-    image_id: String,
-    text: String, // 文本地址
-    doc_id: String,
-    doc_name: String,
-    positions: Array
+  img: String, // 图片链接
+  image_id: String,
+  text: String, // 文本地址
+  doc_id: String,
+  doc_name: String,
+  positions: Array
 });
 
-const DOC_WIDTH = window.innerWidth/2;
+const DOC_WIDTH = window.innerWidth / 2;
 
 const pdf_url = getDocumentUrl(props.doc_id);
 const img_url = getImageUrl(props.image_id);
@@ -61,40 +69,39 @@ const img_url = getImageUrl(props.image_id);
 const visible = ref(false);
 
 const handleClick = () => {
-    const doc_nm = props.doc_name;
+  const doc_nm = props.doc_name;
 
-    if(doc_nm && doc_nm.indexOf('.pdf') === doc_nm.length - 4){
-        visible.value = true;
-    }else{
-        
-    }
+  if (doc_nm && doc_nm.indexOf('.pdf') === doc_nm.length - 4) {
+    visible.value = true;
+  } else {
+  }
 };
 const handleOk = () => {
-    visible.value = false;
+  visible.value = false;
 };
 const handleCancel = () => {
-    visible.value = false;
-}
+  visible.value = false;
+};
 </script>
 
 <style scoped>
-.refference-content{
-    display: flex;
-    justify-content: space-between;
-    align-items: flex-start;
+.refference-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
 }
-.refference-description{
-    flex-grow: 1;
+.refference-description {
+  flex-grow: 1;
 }
 
-.ref-text-content{
-    max-width: 460px;
-    max-height: 340px;
-    overflow-y: auto;
+.ref-text-content {
+  max-width: 460px;
+  max-height: 340px;
+  overflow-y: auto;
 }
 </style>
 <style>
-.arco-drawer-container[data-flag=doc-ref-effect-contaienr] .arco-drawer-body{
-    overflow: hidden;
+.arco-drawer-container[data-flag='doc-ref-effect-contaienr'] .arco-drawer-body {
+  overflow: hidden;
 }
 </style>

+ 33 - 31
src/components/btn-iframe-chujuan/BtnIframeChujuan.vue

@@ -1,13 +1,16 @@
 <template>
-  <a-button @click="handleClick" class="chujuan-btn">
-    <img class="chujuan-logo-img" :src="logo" /> 出卷
-  </a-button>
-
-  <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel" modal-class="chujuan-container-modal" body-class="chujuan-container-body" width="90%">
-    <template #title>
-      <img class="chujuan-logo-img" :src="logo" /> 出卷
-    </template>
-    
+  <a-button @click="handleClick" class="chujuan-btn"> <img class="chujuan-logo-img" :src="logo" /> 出卷 </a-button>
+
+  <a-modal
+    v-model:visible="visible"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    modal-class="chujuan-container-modal"
+    body-class="chujuan-container-body"
+    width="90%"
+  >
+    <template #title> <img class="chujuan-logo-img" :src="logo" /> 出卷 </template>
+
     <iframe :src="iframe_src" class="chujuan-iframe"></iframe>
   </a-modal>
 </template>
@@ -15,9 +18,9 @@
 <script setup>
 import { ref } from 'vue';
 
-import logo from '../../assets/question/1.png'
+import logo from '../../assets/question/1.png';
 
-import {IFRAME_URL_CHUJUAN} from '../../ajax/url-external-config';
+import { IFRAME_URL_CHUJUAN } from '../../ajax/url-external-config';
 
 // const iframe_src = 'http://192.168.20.119:8501';
 const iframe_src = IFRAME_URL_CHUJUAN;
@@ -25,38 +28,37 @@ const iframe_src = IFRAME_URL_CHUJUAN;
 const visible = ref(false);
 
 const handleClick = () => {
-    visible.value = true;
+  visible.value = true;
 };
 const handleOk = () => {
-    visible.value = false;
+  visible.value = false;
 };
 const handleCancel = () => {
-    visible.value = false;
-}
+  visible.value = false;
+};
 </script>
 
 <style scoped>
-.chujuan-btn{
-    border-radius: 30px;
-    color: #353535;
+.chujuan-btn {
+  border-radius: 30px;
+  color: #353535;
 }
-.chujuan-logo-img{
-    width: 22px;
-    display: inline-block;
-    margin-right: 5px;
+.chujuan-logo-img {
+  width: 22px;
+  display: inline-block;
+  margin-right: 5px;
 }
 </style>
 
 <style>
-.chujuan-container-modal{
-
+.chujuan-container-modal {
 }
-.arco-modal-body.chujuan-container-body{
-    width: 100%;
-    padding: 0;
+.arco-modal-body.chujuan-container-body {
+  width: 100%;
+  padding: 0;
 }
-.arco-modal-body.chujuan-container-body .chujuan-iframe{
-    width: 100%;
-    height: 80vh;
+.arco-modal-body.chujuan-container-body .chujuan-iframe {
+  width: 100%;
+  height: 80vh;
 }
-</style>
+</style>

+ 33 - 31
src/components/btn-iframe-comfyui/BtnIframeComfyui.vue

@@ -1,21 +1,24 @@
 <template>
-  <a-button @click="handleClick" class="comfyui-btn">
-    <img class="comfyui-logo-img" :src="logo" /> ComfyUI
-  </a-button>
-
-  <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel" modal-class="comfyui-container-modal" body-class="comfyui-container-body" width="90%">
-    <template #title>
-      <img class="comfyui-logo-img" :src="logo" /> ComfyUI
-    </template>
-    
+  <a-button @click="handleClick" class="comfyui-btn"> <img class="comfyui-logo-img" :src="logo" /> ComfyUI </a-button>
+
+  <a-modal
+    v-model:visible="visible"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    modal-class="comfyui-container-modal"
+    body-class="comfyui-container-body"
+    width="90%"
+  >
+    <template #title> <img class="comfyui-logo-img" :src="logo" /> ComfyUI </template>
+
     <iframe :src="comfyui_src" class="comfyui-iframe"></iframe>
   </a-modal>
 </template>
 
 <script setup>
 import { ref } from 'vue';
-import logo from '../../assets/images/comfyui-logo.png'
-import {IFRAME_URL_COMFYUI} from '../../ajax/url-external-config';
+import logo from '../../assets/images/comfyui-logo.png';
+import { IFRAME_URL_COMFYUI } from '../../ajax/url-external-config';
 
 // const comfyui_src = 'http://192.168.20.119:8188';
 const comfyui_src = IFRAME_URL_COMFYUI;
@@ -23,38 +26,37 @@ const comfyui_src = IFRAME_URL_COMFYUI;
 const visible = ref(false);
 
 const handleClick = () => {
-    visible.value = true;
+  visible.value = true;
 };
 const handleOk = () => {
-    visible.value = false;
+  visible.value = false;
 };
 const handleCancel = () => {
-    visible.value = false;
-}
+  visible.value = false;
+};
 </script>
 
 <style scoped>
-.comfyui-btn{
-    border-radius: 30px;
-    color: #353535;
+.comfyui-btn {
+  border-radius: 30px;
+  color: #353535;
 }
-.comfyui-logo-img{
-    width: 22px;
-    display: inline-block;
-    margin-right: 5px;
+.comfyui-logo-img {
+  width: 22px;
+  display: inline-block;
+  margin-right: 5px;
 }
 </style>
 
 <style>
-.comfyui-container-modal{
-
+.comfyui-container-modal {
 }
-.arco-modal-body.comfyui-container-body{
-    width: 100%;
-    padding: 0;
+.arco-modal-body.comfyui-container-body {
+  width: 100%;
+  padding: 0;
 }
-.arco-modal-body.comfyui-container-body .comfyui-iframe{
-    width: 100%;
-    height: 80vh;
+.arco-modal-body.comfyui-container-body .comfyui-iframe {
+  width: 100%;
+  height: 80vh;
 }
-</style>
+</style>

+ 21 - 21
src/components/btn-manage-doc/BtnMangeDoc.vue

@@ -1,41 +1,41 @@
 <template>
-    <a-button @click="handleClick" class="manage-doc-btn">
-        <img class="chujuan-logo-img" :src="logo" /> 管理文档
-    </a-button>
+  <a-button @click="handleClick" class="manage-doc-btn">
+    <img class="chujuan-logo-img" :src="logo" /> 管理文档
+  </a-button>
 </template>
 
 <script setup>
 import { ref, inject } from 'vue';
 
-import logo from '../../assets/question/1.png'
+import logo from '../../assets/question/1.png';
 
 // import { REDIRECT_URL_BISHENG } from '../../ajax/url-external-config';
 
-const { ajax } = inject("$global");
+const { ajax } = inject('$global');
 
 const handleClick = async () => {
-    const { bisheng_token } = await ajax.user.getToken();
+  const { bisheng_token } = await ajax.user.getToken();
 
-    // "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ7XCJ1c2VyX25hbWVcIjogXCJ1c2VyNFwiLCBcInVzZXJfaWRcIjogMTA3LCBcInJvbGVcIjogWzJdfSIsImlhdCI6MTczMzI4MzQ2NywibmJmIjoxNzMzMjgzNDY3LCJqdGkiOiI2OGU5OWJlMy1lOTBkLTRjYmYtOGMxYS0wODVkYmYxYjk2ZWQiLCJleHAiOjE3MzMzNjk4NjcsInR5cGUiOiJhY2Nlc3MiLCJmcmVzaCI6ZmFsc2V9.OzsrRcCDjU-0La4Md1azLVHwt6R1vtifUMEMU6XX4UE"
-    if (bisheng_token) {
-        // const url = `${REDIRECT_URL_BISHENG}/filelib?token=${bisheng_token}`;
-        const url = `http://${window.location.hostname}:13001/filelib?token=${bisheng_token}`;
+  // "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ7XCJ1c2VyX25hbWVcIjogXCJ1c2VyNFwiLCBcInVzZXJfaWRcIjogMTA3LCBcInJvbGVcIjogWzJdfSIsImlhdCI6MTczMzI4MzQ2NywibmJmIjoxNzMzMjgzNDY3LCJqdGkiOiI2OGU5OWJlMy1lOTBkLTRjYmYtOGMxYS0wODVkYmYxYjk2ZWQiLCJleHAiOjE3MzMzNjk4NjcsInR5cGUiOiJhY2Nlc3MiLCJmcmVzaCI6ZmFsc2V9.OzsrRcCDjU-0La4Md1azLVHwt6R1vtifUMEMU6XX4UE"
+  if (bisheng_token) {
+    // const url = `${REDIRECT_URL_BISHENG}/filelib?token=${bisheng_token}`;
+    const url = `http://${window.location.hostname}:13001/filelib?token=${bisheng_token}`;
 
-        window.open(url, '_blank');
-    }
+    window.open(url, '_blank');
+  }
 };
 </script>
 
 <style scoped>
-.manage-doc-btn{
-    border-radius: 30px;
-    color: #353535;
-    position: absolute;
-    right: 18px
+.manage-doc-btn {
+  border-radius: 30px;
+  color: #353535;
+  position: absolute;
+  right: 18px;
 }
-.chujuan-logo-img{
-    width: 22px;
-    display: inline-block;
-    margin-right: 5px;
+.chujuan-logo-img {
+  width: 22px;
+  display: inline-block;
+  margin-right: 5px;
 }
 </style>

+ 50 - 54
src/components/dialog-wrap/Answer.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script setup>
-import { ref, onBeforeUnmount, onMounted, reactive, nextTick, inject, computed, watch } from "vue";
+import { ref, onBeforeUnmount, onMounted, reactive, nextTick, inject, computed, watch } from 'vue';
 
 import formatAnwserString from '../answer-effect/format-anwser-string';
 
@@ -11,77 +11,73 @@ import applyRefferencePopover from '../answer-effect/apply-refference-popover';
 import applyImageDisplay from '../answer-effect/apply-image-display';
 
 const props = defineProps({
-    /**
-     * 回答的文本数据
-     */
-    answer: String,
-    /**
-     * 界面中对话的序号
-     */
-    index: Number,
-    /**
-     * 当前对话的ID值
-     */
-    chat_id: String,
-    /**
-     * 当前对话的类型
-     */
-    chat_type: String,
-    /**
-     * 当前对话使用的agent ID
-     */
-    agentId: String,
+  /**
+   * 回答的文本数据
+   */
+  answer: String,
+  /**
+   * 界面中对话的序号
+   */
+  index: Number,
+  /**
+   * 当前对话的ID值
+   */
+  chat_id: String,
+  /**
+   * 当前对话的类型
+   */
+  chat_type: String,
+  /**
+   * 当前对话使用的agent ID
+   */
+  agentId: String,
 
-    /**
-     * 特殊数据:专为文档引用效果提供的数据
-     * 文档引用功能需要使用此数据实现
-     */
-    special_4_refference: Object,
-    /**
-     * 特殊数据:专为图片效果提供的数据
-     * 例如:['https://xxx.com/ancd.jpg']
-     */
-    special_4_image: Array,
+  /**
+   * 特殊数据:专为文档引用效果提供的数据
+   * 文档引用功能需要使用此数据实现
+   */
+  special_4_refference: Object,
+  /**
+   * 特殊数据:专为图片效果提供的数据
+   * 例如:['https://xxx.com/ancd.jpg']
+   */
+  special_4_image: Array
 });
 
 const getHTML = (string) => {
-    return formatAnwserString(string);
+  return formatAnwserString(string);
 };
 
 const display_answer = computed(() => {
-    return getHTML(props.answer)
+  return getHTML(props.answer);
 });
 
 const anwser_klass = computed(() => {
-    return `${props.chat_type}-${props.agentId}-answer-content-${props.index}`;
+  return `${props.chat_type}-${props.agentId}-answer-content-${props.index}`;
 });
 
 watch(props.special_4_image, () => {
-    const container_klass = anwser_klass.value;
+  const container_klass = anwser_klass.value;
 
-    /**
-     * 小数绘图的文生图 图片效果
-     */
-    applyImageDisplay(container_klass, props.special_4_image);
+  /**
+   * 小数绘图的文生图 图片效果
+   */
+  applyImageDisplay(container_klass, props.special_4_image);
 });
 
 onMounted(() => {
-    const container_klass = anwser_klass.value;
+  const container_klass = anwser_klass.value;
 
-    /**
-     * 小数绘图的文生图 图片效果
-     */
-    applyImageDisplay(container_klass, props.special_4_image);
+  /**
+   * 小数绘图的文生图 图片效果
+   */
+  applyImageDisplay(container_klass, props.special_4_image);
 
-    /**
-     * 文档引用效果
-     */
-    applyRefferencePopover(container_klass, props.special_4_refference);
+  /**
+   * 文档引用效果
+   */
+  applyRefferencePopover(container_klass, props.special_4_refference);
 });
 </script>
-<style>
-
-</style>
-<style scoped>
-
-</style>
+<style></style>
+<style scoped></style>

+ 7 - 8
src/components/dialog-wrap/ClientUserAvatar.vue

@@ -1,18 +1,17 @@
 <template>
-<div class="user-name" style="background-color: rgb(255, 110, 110)">
+  <div class="user-name" style="background-color: rgb(255, 110, 110)">
     {{ u_name_display }}
-</div>
+  </div>
 </template>
 
 <script setup>
-import { ref, inject, computed } from "vue";
+import { ref, inject, computed } from 'vue';
 
-
-const { helper, ajax } = inject("$global");
-const userName = ref(helper.read("userName") || "");
+const { helper, ajax } = inject('$global');
+const userName = ref(helper.read('userName') || '');
 
 const u_name_display = computed(() => {
-    return userName.value.slice(0, 1);
+  return userName.value.slice(0, 1);
 });
 </script>
 
@@ -26,4 +25,4 @@ const u_name_display = computed(() => {
   justify-content: center;
   color: #fff;
 }
-</style>
+</style>

+ 40 - 40
src/components/dialog-wrap/CodeDisplay.vue

@@ -1,13 +1,13 @@
 <template>
-<div :class="container_klass">
-    <p class="dialog-code-footer-title">{{cd_title}}:</p>
+  <div :class="container_klass">
+    <p class="dialog-code-footer-title">{{ cd_title }}:</p>
     <div v-html="code" class="dialog-code-content"></div>
-</div>
+  </div>
 </template>
 <script setup>
-import { defineComponent, ref,  onMounted, computed } from "vue";
+import { defineComponent, ref, onMounted, computed } from 'vue';
 
-import {applyHighLight} from './format-code-string';
+import { applyHighLight } from './format-code-string';
 
 /**
  * 此组件展示对话中的代码
@@ -15,61 +15,61 @@ import {applyHighLight} from './format-code-string';
  */
 
 const props = defineProps({
-    type: String, // 代码类型:python/sql
-    code: String, // 代码内容
-    index: Number, // 对应了序号
+  type: String, // 代码类型:python/sql
+  code: String, // 代码内容
+  index: Number // 对应了序号
 });
 
 /**
  * 容器class
  */
 const container_klass = computed(() => {
-    return `code-display-${props.type}-${props.index}`;
+  return `code-display-${props.type}-${props.index}`;
 });
 
 /**
  * 代码类型展示
  */
 const cd_title = computed(() => {
-    if(props.type === 'python'){
-        return 'Python'
-    }
+  if (props.type === 'python') {
+    return 'Python';
+  }
 
-    if(props.type === 'sql'){
-        return 'SQL'
-    }
+  if (props.type === 'sql') {
+    return 'SQL';
+  }
 
-    return '';
+  return '';
 });
 
 onMounted(() => {
-    applyHighLight(`.${container_klass.value}`);
+  applyHighLight(`.${container_klass.value}`);
 });
 </script>
 
 <style scoped>
-  .dialog-code-footer {
-    border-radius: 12px;
-    font-size: 14px;
-    background-color: #32333c;
-    color: #BCBDC3;
-    margin: 16px 0;
-    margin-left: 50px;
-  }
+.dialog-code-footer {
+  border-radius: 12px;
+  font-size: 14px;
+  background-color: #32333c;
+  color: #bcbdc3;
+  margin: 16px 0;
+  margin-left: 50px;
+}
 
-    .dialog-code-footer-title {
-      font-size: 16px;
-      font-weight: 500;
-      /* margin: 12px 0; */
-      width: 100%;
-      /* padding: 4px 8px; */
-      /* background-color: #3D3F3F; */
-      /* color: #BCBDC3; */
-      color: #3D3F3F;
-    }
+.dialog-code-footer-title {
+  font-size: 16px;
+  font-weight: 500;
+  /* margin: 12px 0; */
+  width: 100%;
+  /* padding: 4px 8px; */
+  /* background-color: #3D3F3F; */
+  /* color: #BCBDC3; */
+  color: #3d3f3f;
+}
 
-    .dialog-code-content{
-        margin-top: 5px;
-        margin-bottom: 5px;
-    }
-</style>
+.dialog-code-content {
+  margin-top: 5px;
+  margin-bottom: 5px;
+}
+</style>

+ 107 - 101
src/components/dialog-wrap/DocRefItem.vue

@@ -1,137 +1,143 @@
 <template>
-    <div>
-        <a-popover :title="knowledge.doc_name" position="left">
-            <!-- 打开pdf文档 需求注掉 -->
-            <!-- <div @click="openDocuementPage(knowledge)" class="doc-ref-container"> -->
-                <!-- 修改为查看详情 -->
-            <div  class="doc-ref-container" @click="goKnowledge(knowledge)">
-                <span class="doc-ref-index">{{ knowledgeIndex + 1 }}</span>
-                <span class="doc-ref-label">{{ knowledge.doc_name }}</span>
-            </div>
-            <template #content>
-                <div class="knowledge-detail">
-                    <div class="knowledge-content">
-                        {{ knowledge.content_ltks }}
-                    </div>
-                    <div class="knowledge-footer">
-                        <p>检索片段</p>
-                        <p>
-                            <span v-for="(content, contentIndex) in knowledge.content_ltks" :key="contentIndex"
-                                :class="{ active: knowledge.page === contentIndex }" @click="() => {
-                                    knowledge.page = contentIndex;
-                                }
-                                    ">{{ contentIndex + 1 }}</span>
-                        </p>
-                        <!-- TODO详情暂时注释 -->
-                        <p @click="goKnowledge(knowledge)">查看详情></p>
-                    </div>
-                </div>
-            </template>
-        </a-popover>
-    </div>
+  <div>
+    <a-popover :title="knowledge.doc_name" position="left">
+      <!-- 打开pdf文档 需求注掉 -->
+      <!-- <div @click="openDocuementPage(knowledge)" class="doc-ref-container"> -->
+      <!-- 修改为查看详情 -->
+      <div class="doc-ref-container" @click="goKnowledge(knowledge)">
+        <span class="doc-ref-index">{{ knowledgeIndex + 1 }}</span>
+        <span class="doc-ref-label">{{ knowledge.doc_name }}</span>
+      </div>
+      <template #content>
+        <div class="knowledge-detail">
+          <div class="knowledge-content">
+            {{ knowledge.content_ltks }}
+          </div>
+          <div class="knowledge-footer">
+            <p>检索片段</p>
+            <p>
+              <span
+                v-for="(content, contentIndex) in knowledge.content_ltks"
+                :key="contentIndex"
+                :class="{ active: knowledge.page === contentIndex }"
+                @click="
+                  () => {
+                    knowledge.page = contentIndex;
+                  }
+                "
+                >{{ contentIndex + 1 }}</span
+              >
+            </p>
+            <!-- TODO详情暂时注释 -->
+            <p @click="goKnowledge(knowledge)">查看详情></p>
+          </div>
+        </div>
+      </template>
+    </a-popover>
+  </div>
 </template>
 <script setup>
-import { defineComponent, ref, onBeforeUnmount, onMounted, reactive, nextTick, inject } from "vue";
-import { defineEmits } from 'vue'
+import { defineComponent, ref, onBeforeUnmount, onMounted, reactive, nextTick, inject } from 'vue';
+import { defineEmits } from 'vue';
 import { getDocumentUrl } from '../../ajax/document';
 
 const props = defineProps({
-    knowledge: Object,
-    knowledgeIndex: Number
+  knowledge: Object,
+  knowledgeIndex: Number
 });
 const emit = defineEmits(['go-document']);
 
 const openDocuementPage = (knowledge) => {
-    const doc_name = knowledge.doc_name;
-    const doc_id = knowledge.id;
+  const doc_name = knowledge.doc_name;
+  const doc_id = knowledge.id;
 
-    // const pdf_url = `http://192.168.20.119:11080/v1/document/get/${doc_id}`;
-    const pdf_url = getDocumentUrl(doc_id);
+  // const pdf_url = `http://192.168.20.119:11080/v1/document/get/${doc_id}`;
+  const pdf_url = getDocumentUrl(doc_id);
 
-    window.open(pdf_url);
-}
+  window.open(pdf_url);
+};
 const goKnowledge = (knowledge) => {
-    emit('go-document', knowledge)
-}
+  emit('go-document', knowledge);
+};
 </script>
 <style scoped>
 .knowledge-detail {
-    width: 320px;
+  width: 320px;
+  padding-top: 20px;
+
+  .knowledge-content {
+    height: 300px;
+    overflow-y: auto;
+    line-height: 30px;
+  }
+
+  .knowledge-footer {
+    border-top: 1px solid rgba(229, 229, 229, 1);
+    margin-top: 20px;
     padding-top: 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
 
-    .knowledge-content {
-        height: 300px;
-        overflow-y: auto;
-        line-height: 30px;
-    }
+    p {
+      &:nth-child(1) {
+        opacity: 0.8;
+      }
 
-    .knowledge-footer {
-        border-top: 1px solid rgba(229, 229, 229, 1);
-        margin-top: 20px;
-        padding-top: 20px;
+      &:nth-child(2) {
+        flex: 1;
         display: flex;
-        justify-content: space-between;
-        align-items: center;
-
-        p {
-            &:nth-child(1) {
-                opacity: 0.8;
-            }
-
-            &:nth-child(2) {
-                flex: 1;
-                display: flex;
-                justify-content: left;
-                margin: 0 30px;
-
-                >span {
-                    margin: 0 5px;
-                    cursor: pointer;
-
-                    &:hover,
-                    &.active {
-                        color: #00aea3;
-                    }
-                }
-            }
-
-            &:nth-child(3) {
-                font-weight: bold;
-                cursor: pointer;
-
-                &:hover {
-                    color: #00aea3;
-                }
-            }
+        justify-content: left;
+        margin: 0 30px;
+
+        > span {
+          margin: 0 5px;
+          cursor: pointer;
+
+          &:hover,
+          &.active {
+            color: #00aea3;
+          }
         }
+      }
+
+      &:nth-child(3) {
+        font-weight: bold;
+        cursor: pointer;
+
+        &:hover {
+          color: #00aea3;
+        }
+      }
     }
+  }
 }
 
 .doc-ref-container {
-    height: 40px;
-    display: inline-flex;
-    align-items: center;
+  height: 40px;
+  display: inline-flex;
+  align-items: center;
 }
 
 .doc-ref-index {
-    display: inline-block;
-    background-color: #00aea333;
-    color: #00aea3;
-    padding: 1px 5px;
-    border-radius: 2px;
-    margin-right: 5px;
-    font-size: 12px;
-
-    /* margin: 0 5px; */
-    cursor: pointer;
+  display: inline-block;
+  background-color: #00aea333;
+  color: #00aea3;
+  padding: 1px 5px;
+  border-radius: 2px;
+  margin-right: 5px;
+  font-size: 12px;
+
+  /* margin: 0 5px; */
+  cursor: pointer;
 }
 
 .doc-ref-label {
-    /* margin: 0 5px; */
-    cursor: pointer;
+  /* margin: 0 5px; */
+  cursor: pointer;
 }
 
 .doc-ref-label:hover {
-    color: #00aea3;
+  color: #00aea3;
 }
 </style>

+ 92 - 92
src/components/dialog-wrap/Question.vue

@@ -3,121 +3,121 @@
 </template>
 
 <script setup>
-import { onMounted, computed, useTemplateRef } from "vue";
+import { onMounted, computed, useTemplateRef } from 'vue';
 
-import {getTempImageInfo} from './temp-image';
-import { getTempDocFile, wendangzhinengDocFileIsDisplay, wendangzhinengSetDocFilesDisplay } from './temp-wendangzhineng-docs';
+import { getTempImageInfo } from './temp-image';
+import {
+  getTempDocFile,
+  wendangzhinengDocFileIsDisplay,
+  wendangzhinengSetDocFilesDisplay
+} from './temp-wendangzhineng-docs';
 
 const props = defineProps({
-    /**
-     * 回答的文本数据
-     */
-    question: String,
-    /**
-     * 界面中对话的序号
-     */
-    index: Number,
-    /**
-     * 当前对话的ID值
-     */
-    chat_id: String,
-    /**
-     * 当前对话的类型
-     */
-    chat_type: String,
-    /**
-     * 当前对话使用的agent ID
-     */
-    agentId: String,
+  /**
+   * 回答的文本数据
+   */
+  question: String,
+  /**
+   * 界面中对话的序号
+   */
+  index: Number,
+  /**
+   * 当前对话的ID值
+   */
+  chat_id: String,
+  /**
+   * 当前对话的类型
+   */
+  chat_type: String,
+  /**
+   * 当前对话使用的agent ID
+   */
+  agentId: String
 });
 
 const container = useTemplateRef('container');
 
 const question_klass = computed(() => {
-    return `${props.chat_type}-${props.agentId}-question-content-${props.index}`;
+  return `${props.chat_type}-${props.agentId}-question-content-${props.index}`;
 });
 
 const showTempImage = () => {
-    const dt = getTempImageInfo(props.agentId, props.index/1 + 1);
+  const dt = getTempImageInfo(props.agentId, props.index / 1 + 1);
 
-    if(!dt){
-        return;
-    }
+  if (!dt) {
+    return;
+  }
 
-    // 需要设置
-    const file = dt.file; // 图片数据
+  // 需要设置
+  const file = dt.file; // 图片数据
 
-    if(!file){
-        return;
-    }
+  if (!file) {
+    return;
+  }
 
-    const div = document.createElement('div');
-    div.style = `width: 200px;height:200px;text-align: center;background-color:#333;`;
-    if (container.value) {
-        container.value.appendChild(div);
-    }
+  const div = document.createElement('div');
+  div.style = `width: 200px;height:200px;text-align: center;background-color:#333;`;
+  if (container.value) {
+    container.value.appendChild(div);
+  }
 
-    var reader = new FileReader();
-    reader.onload = function(e) {
-        var imgElement = document.createElement("img");
+  var reader = new FileReader();
+  reader.onload = function (e) {
+    var imgElement = document.createElement('img');
 
-        imgElement.src = e.target.result;
+    imgElement.src = e.target.result;
 
-        imgElement.style = `width: 100%;max-width: 200px;max-height:200px;`;
+    imgElement.style = `width: 100%;max-width: 200px;max-height:200px;`;
 
-        div.appendChild(imgElement);
-    };
+    div.appendChild(imgElement);
+  };
 
-    reader.readAsDataURL(file);
-}
+  reader.readAsDataURL(file);
+};
 
 const showTempDocName = () => {
-    const files = getTempDocFile();
-
-    if (!files) {
-        return;
-    }
-
-    if (props.index / 1 !== 0) {
-        return;
-    }
-
-    // const is_displayed = wendangzhinengDocFileIsDisplay();
-    // if (is_displayed) {
-    //     // 如果已经显示,则不再显示
-    //     return;
-    // }
-
-    // 如果有数据
-    const client_files = files.client_files;
-    const server_files = files.server_files;
-
-    const ul = document.createElement('ul');
-    ul.setAttribute('style', 'margin:0;font-size: 12px;padding-left: 15px;font-style: italic;');
-
-    server_files.forEach((item) => {
-        const file_name = item.name;
-        const ele = document.createElement('li');
-        ele.innerHTML = `<span>${file_name}</span>`
-        ul.appendChild(ele);
-    });
-
-    if (container.value) {
-        // wendangzhinengSetDocFilesDisplay();
-        container.value.appendChild(ul);
-    }
-}
+  const files = getTempDocFile();
+
+  if (!files) {
+    return;
+  }
+
+  if (props.index / 1 !== 0) {
+    return;
+  }
+
+  // const is_displayed = wendangzhinengDocFileIsDisplay();
+  // if (is_displayed) {
+  //     // 如果已经显示,则不再显示
+  //     return;
+  // }
+
+  // 如果有数据
+  const client_files = files.client_files;
+  const server_files = files.server_files;
+
+  const ul = document.createElement('ul');
+  ul.setAttribute('style', 'margin:0;font-size: 12px;padding-left: 15px;font-style: italic;');
+
+  server_files.forEach((item) => {
+    const file_name = item.name;
+    const ele = document.createElement('li');
+    ele.innerHTML = `<span>${file_name}</span>`;
+    ul.appendChild(ele);
+  });
+
+  if (container.value) {
+    // wendangzhinengSetDocFilesDisplay();
+    container.value.appendChild(ul);
+  }
+};
 
 onMounted(() => {
-    setTimeout(() => {
-        showTempImage();
-        showTempDocName();
-    });
+  setTimeout(() => {
+    showTempImage();
+    showTempDocName();
+  });
 });
 </script>
-<style>
-
-</style>
-<style scoped>
-
-</style>
+<style></style>
+<style scoped></style>

+ 13 - 10
src/components/dialog-wrap/Suggestion.vue

@@ -1,21 +1,24 @@
 <template>
-<div class="section-suggestions">
-    <div :class="['section-suggestion', readonly ? 'disabled' : '']" v-for="(suggestion, key) in suggestions"
-    :key="key" @click="selectSuggestion(suggestion)">
-        {{ suggestion }}<icon-arrow-right />
+  <div class="section-suggestions">
+    <div
+      :class="['section-suggestion', readonly ? 'disabled' : '']"
+      v-for="(suggestion, key) in suggestions"
+      :key="key"
+      @click="selectSuggestion(suggestion)"
+    >
+      {{ suggestion }}<icon-arrow-right />
     </div>
-</div>
+  </div>
 </template>
 <script setup>
 const props = defineProps({
-    suggestions: Array,
-    readonly: Boolean,
+  suggestions: Array,
+  readonly: Boolean
 });
 
 const selectSuggestion = (text) => {
-    if (!props.readonly) {
-
-    }
+  if (!props.readonly) {
+  }
 };
 </script>
 <style>

+ 9 - 9
src/components/dialog-wrap/format-code-string.js

@@ -6,28 +6,28 @@ import 'highlight.js/styles/monokai.css';
  * @param {string} container_klass - 代码所在容器的class值
  */
 export const applyHighLight = (container_klass) => {
-    document.querySelectorAll(`${container_klass} code.hljs`).forEach(el => {
-        hljs.highlightElement(el);
-    });
+  document.querySelectorAll(`${container_klass} code.hljs`).forEach(el => {
+    hljs.highlightElement(el);
+  });
 }
 
 /**
  * 格式化对话返回的python代码
  * 注意!!!此函数体内的代码格式切记注意,不要随意添加换行、空格等,否则会引起代码呈现样式异常
- * @param {string} code_string 
+ * @param {string} code_string
  */
 export const formatCodePython = (code_string) => {
-    return `<pre><code class="hljs language-python">
+  return `<pre><code class="hljs language-python">
 ${code_string}</code></pre>`;
 }
 
 /**
  * 格式化对话返回的sql代码
  * 注意!!!此函数体内的代码格式切记注意,不要随意添加换行、空格等,否则会引起代码呈现样式异常
- * @param {string} code_string 
- * @returns 
+ * @param {string} code_string
+ * @returns
  */
 export const formatCodeSql = (code_string) => {
-    return `<pre><code class="hljs language-sql">
+  return `<pre><code class="hljs language-sql">
 ${code_string}</code></pre>`
-}
+}

+ 76 - 76
src/components/dialog-wrap/format-dialog-item.js

@@ -7,83 +7,83 @@ import formatFieldDownloadUrl from './format-field-download-url';
 const download_server = window.ASSETS_BASE_URL;
 
 const replaceCode = (text, index) => {
-    const icon = `  <span class="circle" data-list-index="${index || 0}"></span>`
-    return text.replace(/##\d\$\$/g, icon);
+  const icon = `  <span class="circle" data-list-index="${index || 0}"></span>`
+  return text.replace(/##\d\$\$/g, icon);
 }
 
 export default function formatDialogItem(item, index) {
-    const client_id = generateClientUniqueId(JSON.stringify(item));
-
-    const result = {
-        /**
-         * 客户端生成的ID
-         * 此数据作为列表唯一的key
-         */
-        client_gen_id: client_id,
-
-        answer: item.answer && replaceCode(item.answer, index),
-        question: item.question,
-        // 如果有引用
-        reference: (item.reference && item.reference.chunks && item.reference.doc_aggs) ? item.reference.doc_aggs.map(reference => {
-            return {
-                id: reference.doc_id,
-                doc_name: reference.doc_name,
-                page: 0,
-                content_ltks: [item.reference.chunks.find(chunk => chunk.doc_id == reference.doc_id).content_ltks]
-            }
-        }) : [],
-
-        // 完整的引用数据: pdf文档引用效果需要使用此数据
-        fullRefference: item.reference,
-        // 合法可用的图片地址
-        fullImageUrls: (() => {
-            if (item.images) {
-                return item.images;
-            } else {
-                return [];
-            }
-        })(),
-
-        // 如果有文件处理完拿第一个,后续有变动再改
-        file: (item.files && item.files.length > 0) ? item.files.map(item => {
-            const port = window.location.port ? `:${window.location.port}` : '';
-            const base_url = `${download_server}`;
-
-            let url = '';
-            if (item.file_url[0] === '/') {
-                url = `${base_url}${item.file_url}`;
-            } else {
-                url = `${base_url}/${item.file_url}`;
-            }
-
-            let file_url = url.replace('/./', '/');
-
-            return {
-                file_type: 'word',
-                file_name: item.file_name,
-                file_url: file_url,
-            }
-        })[0] : null,
-    };
-
-    if (item.download_url) {
-        const file = formatFieldDownloadUrl(item.download_url);
-
-        result.file = file;
-    }
-
-    if (item.code) {
-        result.code = formatCodePython(item.code);
-    }
-
-    if (item.sql) {
-        result.sql = formatCodeSql(item.sql);
-    }
-
-    if (item.image_url) {
-        // const port = window.location.port ? `:${window.location.port}` : '';
-        result.image_url = `${download_server}${item.image_url}`
-    }
-
-    return result;
+  const client_id = generateClientUniqueId(JSON.stringify(item));
+
+  const result = {
+    /**
+     * 客户端生成的ID
+     * 此数据作为列表唯一的key
+     */
+    client_gen_id: client_id,
+
+    answer: item.answer && replaceCode(item.answer, index),
+    question: item.question,
+    // 如果有引用
+    reference: (item.reference && item.reference.chunks && item.reference.doc_aggs) ? item.reference.doc_aggs.map(reference => {
+      return {
+        id: reference.doc_id,
+        doc_name: reference.doc_name,
+        page: 0,
+        content_ltks: [item.reference.chunks.find(chunk => chunk.doc_id == reference.doc_id).content_ltks]
+      }
+    }) : [],
+
+    // 完整的引用数据: pdf文档引用效果需要使用此数据
+    fullRefference: item.reference,
+    // 合法可用的图片地址
+    fullImageUrls: (() => {
+      if (item.images) {
+        return item.images;
+      } else {
+        return [];
+      }
+    })(),
+
+    // 如果有文件处理完拿第一个,后续有变动再改
+    file: (item.files && item.files.length > 0) ? item.files.map(item => {
+      const port = window.location.port ? `:${window.location.port}` : '';
+      const base_url = `${download_server}`;
+
+      let url = '';
+      if (item.file_url[0] === '/') {
+        url = `${base_url}${item.file_url}`;
+      } else {
+        url = `${base_url}/${item.file_url}`;
+      }
+
+      let file_url = url.replace('/./', '/');
+
+      return {
+        file_type: 'word',
+        file_name: item.file_name,
+        file_url: file_url,
+      }
+    })[0] : null,
+  };
+
+  if (item.download_url) {
+    const file = formatFieldDownloadUrl(item.download_url);
+
+    result.file = file;
+  }
+
+  if (item.code) {
+    result.code = formatCodePython(item.code);
+  }
+
+  if (item.sql) {
+    result.sql = formatCodeSql(item.sql);
+  }
+
+  if (item.image_url) {
+    // const port = window.location.port ? `:${window.location.port}` : '';
+    result.image_url = `${download_server}${item.image_url}`
+  }
+
+  return result;
 }

+ 11 - 11
src/components/dialog-wrap/format-field-download-url.js

@@ -4,17 +4,17 @@
  * @returns
  */
 export default function formatFieldDownloadUrl(download_url) {
-    // const file_url = res_data.download_url;
-    const file_url_arr = decodeURIComponent(download_url).split('/');
-    const file_name = file_url_arr[file_url_arr.length - 1]
+  // const file_url = res_data.download_url;
+  const file_url_arr = decodeURIComponent(download_url).split('/');
+  const file_name = file_url_arr[file_url_arr.length - 1]
 
-    const file = {
-        file_type: 'word',
-        // file_url: `http://${window.location.hostname}${port}${file_url}`,
-        // file_url: res_data.download_url,
-        file_url: download_url,
-        file_name: `${file_name}.docx` || '点击下载',
-    }
+  const file = {
+    file_type: 'word',
+    // file_url: `http://${window.location.hostname}${port}${file_url}`,
+    // file_url: res_data.download_url,
+    file_url: download_url,
+    file_name: `${file_name}.docx` || '点击下载',
+  }
 
-    return file;
+  return file;
 }

+ 7 - 7
src/components/dialog-wrap/generate-client-unique-id.js

@@ -2,12 +2,12 @@ import md5 from 'md5';
 
 /**
  * 根据一个字符串,生成一个客户端的ID
- * @param {string} string 
+ * @param {string} string
  */
 export default function generateClientUniqueId(string) {
-    if (!string) {
-        return Date.now() + ''; // 返回当前时间戳
-    } else {
-        return md5(string);
-    }
-}
+  if (!string) {
+    return Date.now() + ''; // 返回当前时间戳
+  } else {
+    return md5(string);
+  }
+}

+ 19 - 19
src/components/dialog-wrap/temp-image.js

@@ -18,35 +18,35 @@ const store = {};
 
 /**
  * 保存临时图片文件
- * @param {File} file 
+ * @param {File} file
  */
 export const huituSetTempImageFile = (file, agentId, chatId) => {
-    temp_file = file;
-    agent_id = agentId;
-    chat_id = chatId;
+  temp_file = file;
+  agent_id = agentId;
+  chat_id = chatId;
 }
 
 /**
  * 记录临时文件的序号
- * @param {number} index 
+ * @param {number} index
  */
 export const huituSetTempImageIndex = (index) => {
-    temp_index = index;
+  temp_index = index;
 
-    store[`${agent_id}-${index}`] = {
-        file: temp_file,
-        index: temp_index,
-        agent_id: agent_id,
-        chat_id: chat_id
-    };
+  store[`${agent_id}-${index}`] = {
+    file: temp_file,
+    index: temp_index,
+    agent_id: agent_id,
+    chat_id: chat_id
+  };
 }
 
 export const getTempImageInfo = (agent_id, index) => {
-    const key = `${agent_id}-${index}`;
+  const key = `${agent_id}-${index}`;
 
-    if (key in store) {
-        return store[key];
-    } else {
-        return null;
-    }
-}
+  if (key in store) {
+    return store[key];
+  } else {
+    return null;
+  }
+}

+ 6 - 6
src/components/dialog-wrap/temp-wendangzhineng-docs.js

@@ -12,27 +12,27 @@ let is_display = false;
  * @param {File} file
  */
 export const wendangzhinengSetTempDocFile = (file) => {
-    temp_file = file;
+  temp_file = file;
 }
 /**
  * 文档是否已经显示
  * @returns
  */
 export const wendangzhinengDocFileIsDisplay = () => {
-    return is_display;
+  return is_display;
 }
 /**
  * 将文档显示状态设置为显示状态
  */
 export const wendangzhinengSetDocFilesDisplay = () => {
-    is_display = true;
+  is_display = true;
 }
 
 export const wendangzhinengClearDocFile = () => {
-    temp_file = null;
-    is_display = false;
+  temp_file = null;
+  is_display = false;
 }
 
 export const getTempDocFile = (agent_id, index) => {
-    return temp_file;
+  return temp_file;
 }

+ 31 - 32
src/components/file/FileNameDisplay.vue

@@ -1,8 +1,8 @@
 <template>
-    <div class="file-name-display" :class="{'file-name-pdf': is_pdf, 'file-name-others': !is_pdf}">
-        <span class="file-name-icon"><img :src="img_src"/></span>
-        <span class="file-name-label">{{file_name}}</span>
-    </div>
+  <div class="file-name-display" :class="{ 'file-name-pdf': is_pdf, 'file-name-others': !is_pdf }">
+    <span class="file-name-icon"><img :src="img_src" /></span>
+    <span class="file-name-label">{{ file_name }}</span>
+  </div>
 </template>
 <script setup>
 import icon_excel from '../../assets/files/excel.svg';
@@ -10,57 +10,56 @@ import icon_word from '../../assets/files/word-01.svg';
 import icon_pdf from '../../assets/files/pdf.44344347.svg';
 
 const props = defineProps({
-    file_name: String,
-    file_id: String,
+  file_name: String,
+  file_id: String
 });
 
 /**
  * 文件后缀名
  */
-const file_endfix = (function(){
-    const arr = props.file_name.split('.');
+const file_endfix = (function () {
+  const arr = props.file_name.split('.');
 
-    const str = arr[arr.length - 1]
+  const str = arr[arr.length - 1];
 
-    return str;
+  return str;
 })();
 
 const is_pdf = file_endfix === 'pdf';
 
 const icon_map = {
-    docx: icon_word,
-    doc: icon_word,
-    pdf: icon_pdf,
-}
+  docx: icon_word,
+  doc: icon_word,
+  pdf: icon_pdf
+};
 
 const img_src = icon_map[file_endfix];
-
 </script>
 <style scoped>
-.file-name-display{
-    display: flex;
-    justify-content: flex-start;
-    align-items: center;
+.file-name-display {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
 }
-.file-name-pdf{
-    cursor: pointer;
+.file-name-pdf {
+  cursor: pointer;
 }
-.file-name-others{
-    cursor: default;
+.file-name-others {
+  cursor: default;
 }
 
-.file-name-icon{
-    display: inline-block;
-    margin-right: 3px;
-    /* height: 22px; */
-    width: 22px
+.file-name-icon {
+  display: inline-block;
+  margin-right: 3px;
+  /* height: 22px; */
+  width: 22px;
 }
 
-.file-name-icon img{
-    width: 100%;
+.file-name-icon img {
+  width: 100%;
 }
 
-.file-name-label{
-    color: blue;
+.file-name-label {
+  color: blue;
 }
 </style>

+ 8 - 8
src/components/footer/index.vue

@@ -5,12 +5,12 @@
 <script lang="ts" setup></script>
 
 <style lang="less" scoped>
-  .footer {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    height: 40px;
-    color: var(--color-text-2);
-    text-align: center;
-  }
+.footer {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 40px;
+  color: var(--color-text-2);
+  text-align: center;
+}
 </style>

+ 28 - 26
src/components/image-editor/ImgEditBtn.vue

@@ -1,22 +1,25 @@
 <template>
-  <a-button @click="handleClick" class="image-edit-btn">
-    编辑图片
-  </a-button>
+  <a-button @click="handleClick" class="image-edit-btn"> 编辑图片 </a-button>
 
-  <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel" modal-class="image-editor-modal" body-class="image-editor-body" width="70%">
-    <template #title>
-      编辑图片
-    </template>
-    
-    <div style="padding:20px; height: 100%;">
-      <TuiImageEditor :image_url="image_url"/>
+  <a-modal
+    v-model:visible="visible"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    modal-class="image-editor-modal"
+    body-class="image-editor-body"
+    width="70%"
+  >
+    <template #title> 编辑图片 </template>
+
+    <div style="padding: 20px; height: 100%">
+      <TuiImageEditor :image_url="image_url" />
     </div>
   </a-modal>
 </template>
 
 <script setup>
 import { ref } from 'vue';
-import logo from '../../assets/images/comfyui-logo.png'
+import logo from '../../assets/images/comfyui-logo.png';
 
 import TuiImageEditor from './TuiImageEditorVue3.vue';
 
@@ -27,18 +30,18 @@ const props = defineProps({
 const visible = ref(false);
 
 const handleClick = () => {
-    visible.value = true;
+  visible.value = true;
 };
 const handleOk = () => {
-    visible.value = false;
+  visible.value = false;
 };
 const handleCancel = () => {
-    visible.value = false;
-}
+  visible.value = false;
+};
 </script>
 
 <style scoped>
-.image-edit-btn{
+.image-edit-btn {
   width: 100px;
   border-radius: 30px;
   color: #353535;
@@ -46,19 +49,18 @@ const handleCancel = () => {
 </style>
 
 <style>
-.image-editor-modal{
-
+.image-editor-modal {
 }
 
-.arco-modal-body.image-editor-body{
-    width: 100%;
-    /* height: 900px; */
-    height: 840px;
-    /* height: 80vh; */
-    padding: 0;
+.arco-modal-body.image-editor-body {
+  width: 100%;
+  /* height: 900px; */
+  height: 840px;
+  /* height: 80vh; */
+  padding: 0;
 }
 
 .tui-image-editor-submenu-item > li > .tui-image-editor-button > div > .tie-mask-image-file {
-    display: block !important;
+  display: block !important;
 }
-</style>
+</style>

+ 9 - 9
src/components/image-editor/TuiImageEditorVue2.vue

@@ -6,19 +6,19 @@ import ImageEditor from 'tui-image-editor';
 
 const includeUIOptions = {
   includeUI: {
-    initMenu: 'filter',
-  },
+    initMenu: 'filter'
+  }
 };
 const editorDefaultOptions = {
   cssMaxWidth: 700,
-  cssMaxHeight: 500,
+  cssMaxHeight: 500
 };
 export default {
   name: 'TuiImageEditor',
   props: {
     includeUi: {
       type: Boolean,
-      default: true,
+      default: true
     },
     /**
      * @see https://nhn.github.io/tui.image-editor/latest/ImageEditor
@@ -27,8 +27,8 @@ export default {
       type: Object,
       default() {
         return editorDefaultOptions;
-      },
-    },
+      }
+    }
   },
   mounted() {
     let options = this.options;
@@ -98,9 +98,9 @@ export default {
 
       return {
         first: firstMethodName,
-        rest: restMethodName,
+        rest: restMethodName
       };
-    },
-  },
+    }
+  }
 };
 </script>

+ 182 - 187
src/components/image-editor/TuiImageEditorVue3.vue

@@ -2,7 +2,7 @@
   <div ref="editor"></div>
 </template>
 <script setup>
-import {useTemplateRef, onMounted, onUnmounted} from 'vue'
+import { useTemplateRef, onMounted, onUnmounted } from 'vue';
 import ImageEditor from 'tui-image-editor';
 import 'tui-color-picker/dist/tui-color-picker.css';
 import 'tui-image-editor/dist/tui-image-editor.css';
@@ -27,13 +27,13 @@ const props = defineProps({
   //   },
   // },
   // 图片地址
-  image_url: String,
+  image_url: String
 });
 
 const includeUIOptions = {
   includeUI: {
-    initMenu: 'filter',
-  },
+    initMenu: 'filter'
+  }
 };
 
 const editor = useTemplateRef('editor');
@@ -41,15 +41,15 @@ const editor = useTemplateRef('editor');
 // 编辑器实例
 let editorInstance = null;
 
-const addEventListener = () =>  {
+const addEventListener = () => {
   // Object.keys(this.$listeners).forEach((eventName) => {
   //   editorInstance.on(eventName, (...args) => this.$emit(eventName, ...args));
   // });
-}
+};
 
 const getRootElement = () => {
   return editor.value;
-}
+};
 
 const invoke = (methodName, ...args) => {
   let result = null;
@@ -64,7 +64,7 @@ const invoke = (methodName, ...args) => {
   }
 
   return result;
-}
+};
 
 const getMethod = (instance, methodName) => {
   const { first, rest } = parseDotMethodName(methodName);
@@ -83,7 +83,7 @@ const getMethod = (instance, methodName) => {
   }
 
   return obj;
-}
+};
 
 const parseDotMethodName = (methodName) => {
   const firstDotIdx = methodName.indexOf('.');
@@ -97,76 +97,76 @@ const parseDotMethodName = (methodName) => {
 
   return {
     first: firstMethodName,
-    rest: restMethodName,
+    rest: restMethodName
   };
-}
+};
 
 const zh_local = {
-  Crop: "裁剪",
+  Crop: '裁剪',
   Load: '替换图片',
-  DeleteAll: "全部删除",
-  Delete: "删除",
-  Undo: "撤销",
-  Redo: "反撤销",
-  Reset: "重置",
-  Flip: "镜像",
-  Rotate: "旋转",
-  Draw: "画",
-  Shape: "形状标注",
-  Icon: "图标标注",
-  Text: "文字标注",
-  Mask: "遮罩",
-  Filter: "滤镜",
-  Bold: "加粗",
-  Italic: "斜体",
-  Underline: "下划线",
-  Left: "左对齐",
-  Center: "居中",
-  Right: "右对齐",
-  Color: "颜色",
-  "Text size": "字体大小",
-  Custom: "自定义",
-  Square: "正方形",
-  Apply: "应用",
-  Cancel: "取消",
-  "Flip X": "X 轴",
-  "Flip Y": "Y 轴",
-  Range: "区间",
-  Stroke: "描边",
-  Fill: "填充",
-  Circle: "圆",
-  Triangle: "三角",
-  Rectangle: "矩形",
-  Free: "曲线",
-  Straight: "直线",
-  Arrow: "箭头",
-  "Arrow-2": "箭头2",
-  "Arrow-3": "箭头3",
-  "Star-1": "星星1",
-  "Star-2": "星星2",
-  Polygon: "多边形",
-  Location: "定位",
-  Heart: "心形",
-  Bubble: "气泡",
-  "Custom icon": "自定义图标",
-  "Load Mask Image": "加载蒙层图片",
-  Grayscale: "灰度",
-  Blur: "模糊",
-  Sharpen: "锐化",
-  Emboss: "浮雕",
-  "Remove White": "除去白色",
-  Distance: "距离",
-  Brightness: "亮度",
-  Noise: "噪音",
-  "Color Filter": "彩色滤镜",
-  Sepia: "棕色",
-  Sepia2: "棕色2",
-  Invert: "负片",
-  Pixelate: "像素化",
-  Threshold: "阈值",
-  Tint: "色调",
-  Multiply: "正片叠底",
-  Blend: "混合色",
+  DeleteAll: '全部删除',
+  Delete: '删除',
+  Undo: '撤销',
+  Redo: '反撤销',
+  Reset: '重置',
+  Flip: '镜像',
+  Rotate: '旋转',
+  Draw: '画',
+  Shape: '形状标注',
+  Icon: '图标标注',
+  Text: '文字标注',
+  Mask: '遮罩',
+  Filter: '滤镜',
+  Bold: '加粗',
+  Italic: '斜体',
+  Underline: '下划线',
+  Left: '左对齐',
+  Center: '居中',
+  Right: '右对齐',
+  Color: '颜色',
+  'Text size': '字体大小',
+  Custom: '自定义',
+  Square: '正方形',
+  Apply: '应用',
+  Cancel: '取消',
+  'Flip X': 'X 轴',
+  'Flip Y': 'Y 轴',
+  Range: '区间',
+  Stroke: '描边',
+  Fill: '填充',
+  Circle: '圆',
+  Triangle: '三角',
+  Rectangle: '矩形',
+  Free: '曲线',
+  Straight: '直线',
+  Arrow: '箭头',
+  'Arrow-2': '箭头2',
+  'Arrow-3': '箭头3',
+  'Star-1': '星星1',
+  'Star-2': '星星2',
+  Polygon: '多边形',
+  Location: '定位',
+  Heart: '心形',
+  Bubble: '气泡',
+  'Custom icon': '自定义图标',
+  'Load Mask Image': '加载蒙层图片',
+  Grayscale: '灰度',
+  Blur: '模糊',
+  Sharpen: '锐化',
+  Emboss: '浮雕',
+  'Remove White': '除去白色',
+  Distance: '距离',
+  Brightness: '亮度',
+  Noise: '噪音',
+  'Color Filter': '彩色滤镜',
+  Sepia: '棕色',
+  Sepia2: '棕色2',
+  Invert: '负片',
+  Pixelate: '像素化',
+  Threshold: '阈值',
+  Tint: '色调',
+  Multiply: '正片叠底',
+  Blend: '混合色',
   Double: '双击',
   Download: '下载图片'
 };
@@ -249,9 +249,7 @@ const theme = {
   // 'colorpicker.button.border': '1px solid #1e1e1e',
   // 'colorpicker.title.color': '#fff',
 
-
-
-// -----------------------
+  // -----------------------
 
   // // image 坐上角度图片
   //   "common.bi.image": "", // 在这里换上你喜欢的logo图片
@@ -332,104 +330,104 @@ const theme = {
   //   "colorpicker.button.border": "1px solid #1e1e1e",
   //   "colorpicker.title.color": "#fff",
 
+  // -----------------------
 
-// -----------------------
-
-    "common.bi.image": "", // 左上角logo图片
-  "common.bisize.width": "0px",
-  "common.bisize.height": "0px",
-  "common.backgroundImage": "none",
-  "common.backgroundColor": "#f3f4f6",
-  "common.border": "1px solid #333",
+  'common.bi.image': '', // 左上角logo图片
+  'common.bisize.width': '0px',
+  'common.bisize.height': '0px',
+  'common.backgroundImage': 'none',
+  'common.backgroundColor': '#f3f4f6',
+  'common.border': '1px solid #333',
 
   // header
-  "header.backgroundImage": "none",
-  "header.backgroundColor": "#f3f4f6",
-  "header.border": "0px",
-  
+  'header.backgroundImage': 'none',
+  'header.backgroundColor': '#f3f4f6',
+  'header.border': '0px',
+
   // load button
-  "loadButton.backgroundColor": "#fff",
-  "loadButton.border": "1px solid #ddd",
-  "loadButton.color": "#222",
-  "loadButton.fontFamily": "NotoSans, sans-serif",
-  "loadButton.fontSize": "12px",
+  'loadButton.backgroundColor': '#fff',
+  'loadButton.border': '1px solid #ddd',
+  'loadButton.color': '#222',
+  'loadButton.fontFamily': 'NotoSans, sans-serif',
+  'loadButton.fontSize': '12px',
   // "loadButton.display": "none", // 隐藏
 
   // download button
-  "downloadButton.backgroundColor": "#fdba3b",
-  "downloadButton.border": "1px solid #fdba3b",
-  "downloadButton.color": "#fff",
-  "downloadButton.fontFamily": "NotoSans, sans-serif",
-  "downloadButton.fontSize": "12px",
+  'downloadButton.backgroundColor': '#fdba3b',
+  'downloadButton.border': '1px solid #fdba3b',
+  'downloadButton.color': '#fff',
+  'downloadButton.fontFamily': 'NotoSans, sans-serif',
+  'downloadButton.fontSize': '12px',
   // "downloadButton.display": "none", // 隐藏
 
   // icons default
-  "menu.normalIcon.color": "#8a8a8a",
-  "menu.activeIcon.color": "#555555",
-  "menu.disabledIcon.color": "#ccc",
-  "menu.hoverIcon.color": "#e9e9e9",
-  "submenu.normalIcon.color": "#8a8a8a",
-  "submenu.activeIcon.color": "#e9e9e9",
-
-  "menu.iconSize.width": "24px",
-  "menu.iconSize.height": "24px",
-  "submenu.iconSize.width": "32px",
-  "submenu.iconSize.height": "32px",
+  'menu.normalIcon.color': '#8a8a8a',
+  'menu.activeIcon.color': '#555555',
+  'menu.disabledIcon.color': '#ccc',
+  'menu.hoverIcon.color': '#e9e9e9',
+  'submenu.normalIcon.color': '#8a8a8a',
+  'submenu.activeIcon.color': '#e9e9e9',
+
+  'menu.iconSize.width': '24px',
+  'menu.iconSize.height': '24px',
+  'submenu.iconSize.width': '32px',
+  'submenu.iconSize.height': '32px',
 
   // submenu primary color
-  "submenu.backgroundColor": "#1e1e1e",
-  "submenu.partition.color": "#858585",
+  'submenu.backgroundColor': '#1e1e1e',
+  'submenu.partition.color': '#858585',
 
   // submenu labels
-  "submenu.normalLabel.color": "#858585",
-  "submenu.normalLabel.fontWeight": "lighter",
-  "submenu.activeLabel.color": "#fff",
-  "submenu.activeLabel.fontWeight": "lighter",
+  'submenu.normalLabel.color': '#858585',
+  'submenu.normalLabel.fontWeight': 'lighter',
+  'submenu.activeLabel.color': '#fff',
+  'submenu.activeLabel.fontWeight': 'lighter',
 
   // checkbox style
-  "checkbox.border": "1px solid #ccc",
-  "checkbox.backgroundColor": "#fff",
+  'checkbox.border': '1px solid #ccc',
+  'checkbox.backgroundColor': '#fff',
 
   // rango style
-  "range.pointer.color": "#fff",
-  "range.bar.color": "#666",
-  "range.subbar.color": "#d1d1d1",
-
-  "range.disabledPointer.color": "#414141",
-  "range.disabledBar.color": "#282828",
-  "range.disabledSubbar.color": "#414141",
-
-  "range.value.color": "#fff",
-  "range.value.fontWeight": "lighter",
-  "range.value.fontSize": "11px",
-  "range.value.border": "1px solid #353535",
-  "range.value.backgroundColor": "#151515",
-  "range.title.color": "#fff",
-  "range.title.fontWeight": "lighter",
+  'range.pointer.color': '#fff',
+  'range.bar.color': '#666',
+  'range.subbar.color': '#d1d1d1',
+
+  'range.disabledPointer.color': '#414141',
+  'range.disabledBar.color': '#282828',
+  'range.disabledSubbar.color': '#414141',
+
+  'range.value.color': '#fff',
+  'range.value.fontWeight': 'lighter',
+  'range.value.fontSize': '11px',
+  'range.value.border': '1px solid #353535',
+  'range.value.backgroundColor': '#151515',
+  'range.title.color': '#fff',
+  'range.title.fontWeight': 'lighter',
 
   // colorpicker style
-  "colorpicker.button.border": "1px solid #1e1e1e",
-  "colorpicker.title.color": "#fff",
+  'colorpicker.button.border': '1px solid #1e1e1e',
+  'colorpicker.title.color': '#fff'
 };
 
-function imgLoaded(url){
+function imgLoaded(url) {
   return new Promise((resolve, reject) => {
     const img = new Image();
     img.crossOrigin = 'Anonymous';
     img.src = url;
-    img.onload = function(){
+    img.onload = function () {
       // 图片加载完成
       resolve(img);
-    }
+    };
 
-    img.onerror = function(e){
+    img.onerror = function (e) {
       reject(e);
-    }
-  })
+    };
+  });
 }
 
 onMounted(() => {
-    imgLoaded(props.image_url).then(img => {
+  imgLoaded(props.image_url)
+    .then((img) => {
       const url = img.src;
 
       const opts = {
@@ -439,16 +437,16 @@ onMounted(() => {
             // path: 'http://localhost/src/assets/slider/logo.jpg',
             path: url,
             // path: base64,
-            name: "image",
+            name: 'image'
           },
-          initMenu: "draw", // 默认打开的菜单项
-          menuBarPosition: "bottom", // 菜单所在的位置
+          initMenu: 'draw', // 默认打开的菜单项
+          menuBarPosition: 'bottom', // 菜单所在的位置
           locale: zh_local, // 本地化语言为中文
           theme: theme
         },
         cssMaxWidth: 1000, // canvas 最大宽度
-        cssMaxHeight: 600, // canvas 最大高度
-      }
+        cssMaxHeight: 600 // canvas 最大高度
+      };
 
       editorInstance = new ImageEditor(editor.value, opts);
       // editorInstance.addImageObject(props.image_url).then(objectProps => {
@@ -458,46 +456,43 @@ onMounted(() => {
       //   console.log(err, 'error-出错了');
       // });
       addEventListener();
-    }).catch(err => {
+    })
+    .catch((err) => {
       console.log(err, '出错了');
     });
 
-
-    // image2Base64(props.image_url).then(base64 => {
-    //   console.log(base64, 'base64 成功');
-
-    //   const opts = {
-    //     includeUI: {
-    //       loadImage: {
-    //         // path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
-    //         // path: 'http://localhost/src/assets/slider/logo.jpg',
-    //         // path: props.image_url,
-    //         path: base64,
-    //         name: "image",
-    //       },
-    //       initMenu: "draw", // 默认打开的菜单项
-    //       menuBarPosition: "bottom", // 菜单所在的位置
-    //       locale: zh_local, // 本地化语言为中文
-    //       theme: theme
-    //     },
-    //     cssMaxWidth: 1000, // canvas 最大宽度
-    //     cssMaxHeight: 600, // canvas 最大高度
-    //   }
-
-    //   editorInstance = new ImageEditor(editor.value, opts);
-    //   // editorInstance.addImageObject(props.image_url).then(objectProps => {
-    //   //   // https://nhn.github.io/tui.image-editor/latest/ImageEditor#addImageObject
-    //   //   console.log(ojectProps.id, 'console.log(ojectProps.id);');
-    //   // }).catch(err => {
-    //   //   console.log(err, 'error-出错了');
-    //   // });
-    //   addEventListener();
-    // }).catch(err => {
-    //   console.log(err, '转base64失败');
-    // });
-    
-
-
+  // image2Base64(props.image_url).then(base64 => {
+  //   console.log(base64, 'base64 成功');
+
+  //   const opts = {
+  //     includeUI: {
+  //       loadImage: {
+  //         // path: "https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1d7a1feb60346449c1a64893888989a~tplv-k3u1fbpfcp-watermark.image",
+  //         // path: 'http://localhost/src/assets/slider/logo.jpg',
+  //         // path: props.image_url,
+  //         path: base64,
+  //         name: "image",
+  //       },
+  //       initMenu: "draw", // 默认打开的菜单项
+  //       menuBarPosition: "bottom", // 菜单所在的位置
+  //       locale: zh_local, // 本地化语言为中文
+  //       theme: theme
+  //     },
+  //     cssMaxWidth: 1000, // canvas 最大宽度
+  //     cssMaxHeight: 600, // canvas 最大高度
+  //   }
+
+  //   editorInstance = new ImageEditor(editor.value, opts);
+  //   // editorInstance.addImageObject(props.image_url).then(objectProps => {
+  //   //   // https://nhn.github.io/tui.image-editor/latest/ImageEditor#addImageObject
+  //   //   console.log(ojectProps.id, 'console.log(ojectProps.id);');
+  //   // }).catch(err => {
+  //   //   console.log(err, 'error-出错了');
+  //   // });
+  //   addEventListener();
+  // }).catch(err => {
+  //   console.log(err, '转base64失败');
+  // });
 });
 
 onUnmounted(() => {
@@ -511,7 +506,7 @@ onUnmounted(() => {
 </script>
 
 <style>
-.image-editor-body .tui-image-editor{
+.image-editor-body .tui-image-editor {
   top: 0 !important;
 }
-</style>
+</style>

+ 23 - 23
src/components/image-editor/img-2-base64.js

@@ -19,30 +19,30 @@
  * 将图片数据转换为base64
  * @see https://blog.csdn.net/weixin_43452154/article/details/134449821
  * @param {string} src - 图片链接
- * @returns 
+ * @returns
  */
 export default function image2Base64(src) {
-    var toBase64 = new Promise(function (resolve, reject) {
-        window.URL = window.URL || window.webkitURL;
-        var xhr = new XMLHttpRequest();
-        xhr.open("get", src, true);
+  var toBase64 = new Promise(function (resolve, reject) {
+    window.URL = window.URL || window.webkitURL;
+    var xhr = new XMLHttpRequest();
+    xhr.open("get", src, true);
+    // 至关重要
+    xhr.responseType = "blob";//文件流
+    xhr.onload = function (res) {
+      if (res.currentTarget.status == 200) {
+        //得到一个blob对象
+        var blob = res.currentTarget.response;
         // 至关重要
-        xhr.responseType = "blob";//文件流
-        xhr.onload = function (res) {
-            if (res.currentTarget.status == 200) {
-                //得到一个blob对象
-                var blob = res.currentTarget.response;
-                // 至关重要
-                let oFileReader = new FileReader();
-                oFileReader.onloadend = function (e) {
-                    let base64 = e.target.result;//base64
-                    resolve(base64)
-                };
-                oFileReader.readAsDataURL(blob);
-            }
-        }
-        xhr.send();
-    });
+        let oFileReader = new FileReader();
+        oFileReader.onloadend = function (e) {
+          let base64 = e.target.result;//base64
+          resolve(base64)
+        };
+        oFileReader.readAsDataURL(blob);
+      }
+    }
+    xhr.send();
+  });
 
-    return toBase64;
-}
+  return toBase64;
+}

+ 242 - 231
src/components/pdf-viewer/PDFViewer.vue

@@ -1,23 +1,21 @@
 <template>
-    <div class="pdf-container" id="pdfContainer" ref="box">
-
-    </div>
-    <div class="loading-pdf-box" v-if="load_status === 2">
-        <div class="loading-spin">
-            <a-spin :size="36" />
-        </div>
-    </div>
-
-    <div class="loading-pdf-box" v-if="load_status === 4">
-        <a-result status="error" title="文档加载出错">
-            <template #subtitle>
-                {{ load_msg }}
-            </template>
-        </a-result>
+  <div class="pdf-container" id="pdfContainer" ref="box"></div>
+  <div class="loading-pdf-box" v-if="load_status === 2">
+    <div class="loading-spin">
+      <a-spin :size="36" />
     </div>
+  </div>
+
+  <div class="loading-pdf-box" v-if="load_status === 4">
+    <a-result status="error" title="文档加载出错">
+      <template #subtitle>
+        {{ load_msg }}
+      </template>
+    </a-result>
+  </div>
 </template>
 <script setup>
-import { defineComponent, inject, ref, useTemplateRef, watch, onMounted, onBeforeUnmount } from "vue";
+import { defineComponent, inject, ref, useTemplateRef, watch, onMounted, onBeforeUnmount } from 'vue';
 
 import PDFJS from './pdfjs';
 
@@ -28,30 +26,30 @@ import { Message } from '@arco-design/web-vue';
  * 此路径指向PDF文件
  */
 const props = defineProps({
-    /**
-     * PDF文档的链接
-     */
-    url: String,
-    /**
-     * 想要展示的PDF文档的宽度
-     * 是一个数字
-     * 例如:800,表示希望PDF文档的每一页展示为800px宽度
-     */
-    doc_width: Number,
-    /**
-     * PDF文档的高亮区域,是一个数组的数组
-     * 例如:[[7, 200, 500, 100, 300], [7, 300, 600, 400, 420]]
-     * 数组中的每一项表示一个高亮区域,数组有几个元素,表示有几个高亮区域
-     * 以示例数据中的第一个高亮区域 [7, 200, 500, 100, 300] 为例
-     * 7 表示高亮区域所处的页码
-     * 200 表示 x1,距离第7页左侧的距离
-     * 500 表示 x2, 距离第7页左侧的距离
-     * 100 表示 y1, 距离第7页顶部的距离
-     * 300 表示 y2, 距离第7页顶部的距离
-     * 最终形成的四个坐标点为:(x1,y1) (x2,y1) (x1,y2) (x2,y2)
-     * 通过这四个坐标点,围合成一个矩形区域
-     */
-    positions: Array,
+  /**
+   * PDF文档的链接
+   */
+  url: String,
+  /**
+   * 想要展示的PDF文档的宽度
+   * 是一个数字
+   * 例如:800,表示希望PDF文档的每一页展示为800px宽度
+   */
+  doc_width: Number,
+  /**
+   * PDF文档的高亮区域,是一个数组的数组
+   * 例如:[[7, 200, 500, 100, 300], [7, 300, 600, 400, 420]]
+   * 数组中的每一项表示一个高亮区域,数组有几个元素,表示有几个高亮区域
+   * 以示例数据中的第一个高亮区域 [7, 200, 500, 100, 300] 为例
+   * 7 表示高亮区域所处的页码
+   * 200 表示 x1,距离第7页左侧的距离
+   * 500 表示 x2, 距离第7页左侧的距离
+   * 100 表示 y1, 距离第7页顶部的距离
+   * 300 表示 y2, 距离第7页顶部的距离
+   * 最终形成的四个坐标点为:(x1,y1) (x2,y1) (x1,y2) (x2,y2)
+   * 通过这四个坐标点,围合成一个矩形区域
+   */
+  positions: Array
 });
 
 const box = useTemplateRef('box');
@@ -60,11 +58,10 @@ const box = useTemplateRef('box');
  *
  */
 let pdfDocument = null;
-const height_list = []
+const height_list = [];
 let pdfCtxs = [];
-let scale_value = 1
-let drawPages = [] //已经绘制的页码
-
+let scale_value = 1;
+let drawPages = []; //已经绘制的页码
 
 /**
  * 记录PDF文档加载过程中的状态
@@ -80,234 +77,248 @@ const load_msg = ref(''); // 加载消息
  * 处理高亮区域
  */
 const highlight_pos = (() => {
-    const mp = {};
-    props.positions.forEach((item, index) => {
-        const page_index = item[0];
-
-        const x1 = item[1];
-        const x2 = item[2];
-        const y1 = item[3];
-        const y2 = item[4];
-
-        if (page_index in mp) {
-            mp[page_index].push({
-                x1,
-                x2,
-                y1,
-                y2
-            });
-        } else {
-            mp[page_index] = [{
-                x1,
-                x2,
-                y1,
-                y2
-            }];
+  const mp = {};
+  props.positions.forEach((item, index) => {
+    const page_index = item[0];
+
+    const x1 = item[1];
+    const x2 = item[2];
+    const y1 = item[3];
+    const y2 = item[4];
+
+    if (page_index in mp) {
+      mp[page_index].push({
+        x1,
+        x2,
+        y1,
+        y2
+      });
+    } else {
+      mp[page_index] = [
+        {
+          x1,
+          x2,
+          y1,
+          y2
         }
+      ];
+    }
+  });
 
-    });
-
-    return mp;
+  return mp;
 })();
 
 /**
  * 绘制高亮区域
  */
 function drawHighLight(ctx, x1, x2, y1, y2) {
-    // 设置矩形的样式
-    ctx.fillStyle = 'rgba(255, 255, 0, 0.5)';  // 填充颜色
-    // ctx.strokeStyle = 'red'; // 边框颜色
-    // ctx.lineWidth = 5;       // 边框宽度
+  // 设置矩形的样式
+  ctx.fillStyle = 'rgba(255, 255, 0, 0.5)'; // 填充颜色
+  // ctx.strokeStyle = 'red'; // 边框颜色
+  // ctx.lineWidth = 5;       // 边框宽度
 
-    const width = x2 - x1;
-    const height = y2 - y1;
+  const width = x2 - x1;
+  const height = y2 - y1;
 
-    // 绘制填充矩形
-    ctx.fillRect(x1, y1, width, height); // 参数依次为:x坐标, y坐标, 宽度, 高度
+  // 绘制填充矩形
+  ctx.fillRect(x1, y1, width, height); // 参数依次为:x坐标, y坐标, 宽度, 高度
 }
 
 function getPageHeight(viewWidth, viewHeight) {
-    const height = props.doc_width / (viewWidth / viewHeight);
+  const height = props.doc_width / (viewWidth / viewHeight);
 
-    return height;
+  return height;
 }
 
 onMounted(() => {
-    load_status.value = 2; // 加载中
-    load_msg.value = 'loading';
-
-    PDFJS.getDocument(props.url).promise.then(async pdfDoc => {
-        pdfDocument = pdfDoc;
-        const page_total = pdfDoc.numPages;
-
-        let min_page = -1;
-        let height_total = 0;
-        height_list.length = 0;
-        pdfCtxs.length = 0;
-
-        for (let i = 1; i <= page_total; i++) {
-            const canvas = document.createElement('canvas');
-            // 设置事件监听器来阻止默认的右键菜单
-            canvas.addEventListener('contextmenu', function (e) {
-                e.preventDefault();
-            });
-            pdfCtxs[i] = canvas.getContext('2d')
-
-            const page = await pdfDoc.getPage(i);
-
-            // 获取原始页面的大小
-            const viewport1 = page.getViewport({ scale: 1 })
-            // 原始宽度和高度
-            const cur_width = viewport1.width;
-            const cur_height = viewport1.height;
-
-            // 目标宽度和高度
-            const target_width = props.doc_width;
-            const target_height = target_width / (cur_width / cur_height);
-
-            // 获取到缩放比例
-            scale_value = target_width / cur_width;
-
-            // 根据缩放比例,重新获取viewport值
-            const viewport2 = page.getViewport({ scale: scale_value });
-
-            // 收集每个文档页面起始位置高度
-            height_list.push(height_total);
-
-            canvas.width = target_width
-            canvas.height = target_height; // viewport.height
-
-            height_total = height_total + canvas.height;
-            await page.render({
-                viewport: viewport2,
-                canvasContext: pdfCtxs[i],
-            })
-                .promise;
-
-            if (i in highlight_pos) {
-                const pos_info = highlight_pos[i]
-                // 记录第一个要跳转的页码
-                if (min_page === -1) {
-                    min_page = i;
-                }
-
-                pos_info.forEach((psinfo) => {
-                    drawHighLight(pdfCtxs[i], psinfo.x1 * scale_value, psinfo.x2 * scale_value, psinfo.y1 * scale_value, psinfo.y2 * scale_value);
-                });
-            }
-
-            box.value && box.value.appendChild(canvas);
+  load_status.value = 2; // 加载中
+  load_msg.value = 'loading';
+
+  PDFJS.getDocument(props.url)
+    .promise.then(async (pdfDoc) => {
+      pdfDocument = pdfDoc;
+      const page_total = pdfDoc.numPages;
+
+      let min_page = -1;
+      let height_total = 0;
+      height_list.length = 0;
+      pdfCtxs.length = 0;
+
+      for (let i = 1; i <= page_total; i++) {
+        const canvas = document.createElement('canvas');
+        // 设置事件监听器来阻止默认的右键菜单
+        canvas.addEventListener('contextmenu', function (e) {
+          e.preventDefault();
+        });
+        pdfCtxs[i] = canvas.getContext('2d');
+
+        const page = await pdfDoc.getPage(i);
+
+        // 获取原始页面的大小
+        const viewport1 = page.getViewport({ scale: 1 });
+        // 原始宽度和高度
+        const cur_width = viewport1.width;
+        const cur_height = viewport1.height;
+
+        // 目标宽度和高度
+        const target_width = props.doc_width;
+        const target_height = target_width / (cur_width / cur_height);
+
+        // 获取到缩放比例
+        scale_value = target_width / cur_width;
+
+        // 根据缩放比例,重新获取viewport值
+        const viewport2 = page.getViewport({ scale: scale_value });
+
+        // 收集每个文档页面起始位置高度
+        height_list.push(height_total);
+
+        canvas.width = target_width;
+        canvas.height = target_height; // viewport.height
+
+        height_total = height_total + canvas.height;
+        await page.render({
+          viewport: viewport2,
+          canvasContext: pdfCtxs[i]
+        }).promise;
+
+        if (i in highlight_pos) {
+          const pos_info = highlight_pos[i];
+          // 记录第一个要跳转的页码
+          if (min_page === -1) {
+            min_page = i;
+          }
+
+          pos_info.forEach((psinfo) => {
+            drawHighLight(
+              pdfCtxs[i],
+              psinfo.x1 * scale_value,
+              psinfo.x2 * scale_value,
+              psinfo.y1 * scale_value,
+              psinfo.y2 * scale_value
+            );
+          });
         }
 
-        // 所有页面都加载完毕,结束加载状态
-        load_status.value = 3; // 加载成功
-        load_msg.value = 'success';
-
+        box.value && box.value.appendChild(canvas);
+      }
 
-        // TODO: 优化跳转效果:平滑跳转
-        if (min_page !== -1) {
-            setTimeout(() => {
-                box.value.scrollTop = height_list[min_page - 1]
-            });
-        }
-    }).catch(err => {
-        console.log(err, 'PDF加载出错');
-        // Message.error(err.message);
+      // 所有页面都加载完毕,结束加载状态
+      load_status.value = 3; // 加载成功
+      load_msg.value = 'success';
 
-        load_status.value = 4; // 加载出错
-        load_msg.value = `PDF文档 ${props.url} 加载出错。 ERROR: :${err.message}`;
+      // TODO: 优化跳转效果:平滑跳转
+      if (min_page !== -1) {
+        setTimeout(() => {
+          box.value.scrollTop = height_list[min_page - 1];
+        });
+      }
+    })
+    .catch((err) => {
+      console.log(err, 'PDF加载出错');
+      // Message.error(err.message);
+
+      load_status.value = 4; // 加载出错
+      load_msg.value = `PDF文档 ${props.url} 加载出错。 ERROR: :${err.message}`;
     });
-})
+});
 
 const highlight_position = (positions) => {
-    const mp = {};
-    positions.forEach((item, index) => {
-        const page_index = item[0];
-
-        const x1 = item[1];
-        const x2 = item[2];
-        const y1 = item[3];
-        const y2 = item[4];
-
-        if (page_index in mp) {
-            mp[page_index].push({
-                x1,
-                x2,
-                y1,
-                y2
-            });
-        } else {
-            mp[page_index] = [{
-                x1,
-                x2,
-                y1,
-                y2
-            }];
+  const mp = {};
+  positions.forEach((item, index) => {
+    const page_index = item[0];
+
+    const x1 = item[1];
+    const x2 = item[2];
+    const y1 = item[3];
+    const y2 = item[4];
+
+    if (page_index in mp) {
+      mp[page_index].push({
+        x1,
+        x2,
+        y1,
+        y2
+      });
+    } else {
+      mp[page_index] = [
+        {
+          x1,
+          x2,
+          y1,
+          y2
         }
-
-    });
-    return mp;
-}
-const toPageIndex = async (pageNumber, positions) => {
-    if (!pdfDocument) {
-        return
+      ];
     }
-    setTimeout(() => {
-        box.value.scrollTop = height_list[pageNumber - 1]
+  });
+  return mp;
+};
+const toPageIndex = async (pageNumber, positions) => {
+  if (!pdfDocument) {
+    return;
+  }
+  setTimeout(() => {
+    box.value.scrollTop = height_list[pageNumber - 1];
+  });
+  if (!drawPages.includes(pageNumber)) {
+    const highPos = highlight_position(positions);
+    highPos[pageNumber]?.forEach((psinfo) => {
+      drawHighLight(
+        pdfCtxs[pageNumber],
+        psinfo.x1 * scale_value,
+        psinfo.x2 * scale_value,
+        psinfo.y1 * scale_value,
+        psinfo.y2 * scale_value
+      );
+      // drawHighLight(pdfCtxs[pageNumber], psinfo.x1 * scale_value.value, psinfo.x2 * scale_value.value, psinfo.y1 * scale_value.value, psinfo.y2 * scale_value.value);
+      drawPages.push(pageNumber);
     });
-    if (!drawPages.includes(pageNumber)) {
-        const highPos = highlight_position(positions)
-        highPos[pageNumber]?.forEach(psinfo => {
-            drawHighLight(pdfCtxs[pageNumber], psinfo.x1 * scale_value, psinfo.x2 * scale_value, psinfo.y1 * scale_value, psinfo.y2 * scale_value)
-            // drawHighLight(pdfCtxs[pageNumber], psinfo.x1 * scale_value.value, psinfo.x2 * scale_value.value, psinfo.y1 * scale_value.value, psinfo.y2 * scale_value.value);
-            drawPages.push(pageNumber)
-        });
-    }
-}
+  }
+};
 
 const drawHighLightArea = (pdfCtx, x1, x2, y1, y2) => {
-    // 设置高亮的样式,比如颜色、透明度、线宽等
-    pdfCtx.fillStyle = "rgba(255, 255, 0, 0.5)"; // 黄色半透明
-    // 绘制高亮矩形
-    pdfCtx.beginPath();
-    pdfCtx.rect(x1, y1, x2 - x1, y2 - y1);
-    pdfCtx.fill(); // 填充矩形
+  // 设置高亮的样式,比如颜色、透明度、线宽等
+  pdfCtx.fillStyle = 'rgba(255, 255, 0, 0.5)'; // 黄色半透明
+  // 绘制高亮矩形
+  pdfCtx.beginPath();
+  pdfCtx.rect(x1, y1, x2 - x1, y2 - y1);
+  pdfCtx.fill(); // 填充矩形
 };
 onBeforeUnmount(() => {
-    pdfCtxs.forEach(ctx => {
-        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
-    });
-    pdfCtxs.length = 0;
-    height_list.length = 0;
-    pdfDocument = null;
-})
+  pdfCtxs.forEach((ctx) => {
+    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+  });
+  pdfCtxs.length = 0;
+  height_list.length = 0;
+  pdfDocument = null;
+});
 
 defineExpose({
-    toPageIndex
-})
+  toPageIndex
+});
 </script>
 <style scoped>
 .pdf-container {
-    text-align: center;
-    height: 100vh;
-    overflow-y: auto;
+  text-align: center;
+  height: 100vh;
+  overflow-y: auto;
 }
 
 .loading-pdf-box {
-    width: 100%;
-    height: 100vh;
-    display: flex;
-    text-align: center;
-    justify-content: center;
-    align-items: center;
-    position: absolute;
-    top: 0;
-    left: 0;
-    background-color: #fff;
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  text-align: center;
+  justify-content: center;
+  align-items: center;
+  position: absolute;
+  top: 0;
+  left: 0;
+  background-color: #fff;
 }
 
 .loading-spin {
-    width: 40px;
-    height: 40px;
+  width: 40px;
+  height: 40px;
 }
 </style>

+ 31 - 28
src/components/pdf-viewer/PdfReader.vue

@@ -2,16 +2,15 @@
   <div class="doc-viewer" ref="elementRef"></div>
 </template>
 <script>
-import '../../../public/pdf/image-viewer.umd'
-import '../../../public/pdf/style.css'
-import { defineComponent, onMounted, ref } from 'vue'
+import '../../../public/pdf/image-viewer.umd';
+import '../../../public/pdf/style.css';
+import { defineComponent, onMounted, ref } from 'vue';
 export default defineComponent({
-  components: {
-  },
+  components: {},
   props: ['fileUrl', 'fileName'],
-  setup(props, {emit}) {
+  setup(props, { emit }) {
     const elementRef = ref(null);
-    onMounted(()=>{
+    onMounted(() => {
       const options = {
         defaultUrl: props.fileUrl,
         resourcePath: 'pdf/',
@@ -24,15 +23,15 @@ export default defineComponent({
         appConfig: {
           toolbar: {
             toolbarViewerLeft: {
-              pageNumber: false,
-            },
-          },
+              pageNumber: false
+            }
+          }
         },
         toolbarControl: {
-          download: false,
+          download: false
         },
         locale: 'zh-cn'
-      }
+      };
       const app = ImageViewer.createViewer(elementRef.value, options);
       app.readyPromise.then(() => {
         document.querySelector('#pdfFileName').innerHTML = props.fileName;
@@ -41,32 +40,36 @@ export default defineComponent({
     return {
       elementRef
     };
-  },
+  }
 });
 </script>
 <style>
 html[dir='ltr'] [data-id='toolbarViewerRight'] {
-	display: none;
+  display: none;
 }
 .pdf-document-viewer .toolbar {
-	z-index: 999;
+  z-index: 999;
 }
 .pdf-document-viewer .annotation-control-bar__bottom {
-	opacity: 0;
-	display: none;
+  opacity: 0;
+  display: none;
 }
-.pdf-document-viewer  .annotation[data-subtype=Highlight][data-custom-type=search] .annotation-quad{
-	fill: rgba(250,200,80,.3);	
+.pdf-document-viewer .annotation[data-subtype='Highlight'][data-custom-type='search'] .annotation-quad {
+  fill: rgba(250, 200, 80, 0.3);
 }
 
-.pdf-document-viewer  .annotation[data-subtype=Highlight][data-custom-type=search] .widget-content{
-  fill: rgba(250,200,80,.3);
+.pdf-document-viewer .annotation[data-subtype='Highlight'][data-custom-type='search'] .widget-content {
+  fill: rgba(250, 200, 80, 0.3);
 }
-[data-id=toolbarContainer], .findbar, .secondaryToolbar {
+[data-id='toolbarContainer'],
+.findbar,
+.secondaryToolbar {
   height: 50px;
   padding-left: 50px;
 }
-.pdf-document-viewer input, .pdf-document-viewer button, .pdf-document-viewer select {
+.pdf-document-viewer input,
+.pdf-document-viewer button,
+.pdf-document-viewer select {
   border: none;
   cursor: pointer;
 }
@@ -74,12 +77,12 @@ html[dir='ltr'] [data-id='toolbarViewerRight'] {
   margin-top: 8px;
   flex: 1;
 }
-[data-id=toolbarViewerLeft] {
+[data-id='toolbarViewerLeft'] {
   display: flex;
 }
 </style>
 <style scoped>
-  .doc-viewer {
-    height: 100%;
-  }
-</style>
+.doc-viewer {
+  height: 100%;
+}
+</style>

+ 1 - 1
src/components/pdf-viewer/pdfjs.js

@@ -4,4 +4,4 @@ import * as PDFJS from './pdf.min.mjs'
 // PDFJS.GlobalWorkerOptions.workerSrc = `/pdfjs-dist/pdf.worker.mjs`
 PDFJS.GlobalWorkerOptions.workerSrc = `/pdfjs-dist/pdf.worker.min.js`
 
-export default PDFJS;
+export default PDFJS;

+ 39 - 41
src/components/picture-upload/BtnImgDelete.vue

@@ -1,45 +1,44 @@
 <template>
-<a-popover :popup-visible="showDeleteTooltip">
+  <a-popover :popup-visible="showDeleteTooltip">
     <a-tooltip content="删除">
-        <div class="method-button" @click="handleDeleteButton">
-            <icon-delete />
-        </div>
+      <div class="method-button" @click="handleDeleteButton">
+        <icon-delete />
+      </div>
     </a-tooltip>
-    
+
     <template #content>
-        <div>
+      <div>
         <p>删除后无法恢复,您是否删除?</p>
         <div class="delete-buttons">
-            <div>
-            <a-button size="mini" type="primary" style="margin-right: 10px"
-                @click="deleteDocument">确认</a-button>
+          <div>
+            <a-button size="mini" type="primary" style="margin-right: 10px" @click="deleteDocument">确认</a-button>
             <a-button size="mini" type="outline" @click="handleCancelDelete">取消</a-button>
-            </div>
-        </div>
+          </div>
         </div>
+      </div>
     </template>
-</a-popover>
+  </a-popover>
 </template>
 <script setup>
-import { defineComponent, ref, inject, reactive } from "vue";
+import { defineComponent, ref, inject, reactive } from 'vue';
 
 const emit = defineEmits(['delete']);
 
 const showDeleteTooltip = ref(false);
 
 const handleCancelDelete = () => {
-    showDeleteTooltip.value = false;
+  showDeleteTooltip.value = false;
 };
 
 const handleDeleteButton = () => {
-    showDeleteTooltip.value = true;
+  showDeleteTooltip.value = true;
 };
 
 /**
  * 确认删除
  */
 const deleteDocument = () => {
-    emit('delete');
+  emit('delete');
 };
 </script>
 
@@ -48,7 +47,7 @@ const deleteDocument = () => {
   display: flex;
   justify-content: right;
 
-  >div {
+  > div {
     display: flex;
   }
 }
@@ -71,11 +70,11 @@ const deleteDocument = () => {
 }
 
 /**宽度占位 */
-.placeholder-width-5px{
+.placeholder-width-5px {
   display: inline-block;
   width: 10px;
 }
-.pictures-upload-info{
+.pictures-upload-info {
   display: flex;
   align-items: center;
   justify-content: flex-start;
@@ -84,30 +83,30 @@ const deleteDocument = () => {
 .upload-main {
   width: 800px;
   height: 109px;
-  background: url("@/assets/document/upload.svg");
+  background: url('@/assets/document/upload.svg');
   margin: 0 auto;
   padding: 24px 0px 24px 277px;
   background-size: 100%;
 
-  >p {
+  > p {
     color: #000;
     font-weight: bold;
     margin-bottom: 5px;
     margin-top: 10px;
 
-    >span {
+    > span {
       color: #00aea3;
       text-decoration: underline;
     }
   }
 
-  >span {
+  > span {
     font-size: 13px;
     color: #7f7f7f;
   }
 }
 
-footer.picture-upload-footer{
+footer.picture-upload-footer {
   display: flex;
   justify-content: flex-start;
   align-items: center;
@@ -119,7 +118,7 @@ footer.picture-upload-footer{
     align-items: center;
   }
 
-  .upload-img-container{
+  .upload-img-container {
     cursor: pointer;
     // width: 110px;
     height: 32px;
@@ -142,7 +141,7 @@ footer.picture-upload-footer{
       }
     }
 
-    >img {
+    > img {
       width: 110px;
       height: 32px;
     }
@@ -198,14 +197,13 @@ main {
   //   }
   // }
 
-
-  >footer {
+  > footer {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-top: auto;
 
-    >div {
+    > div {
       display: inline-flex;
       align-items: center;
       gap: 8px;
@@ -228,17 +226,17 @@ main {
         width: 100px;
         overflow: hidden;
 
-        >div>img {
+        > div > img {
           width: 100px;
         }
       }
 
-      >p {
+      > p {
         overflow: hidden;
         white-space: nowrap;
       }
 
-      >div {
+      > div {
         cursor: pointer;
         width: 110px;
         height: 32px;
@@ -261,21 +259,21 @@ main {
           }
         }
 
-        >img {
+        > img {
           width: 110px;
           height: 32px;
         }
       }
     }
 
-    >section {
+    > section {
       display: flex;
       align-items: center;
       background: rgba(150, 171, 185, 0.2);
       border-radius: 20px;
       padding: 5px 10px;
 
-      >p {
+      > p {
         margin-right: 5px;
       }
     }
@@ -293,18 +291,18 @@ main {
     height: auto;
   }
 
-  >header {
+  > header {
     display: flex;
     align-items: center;
     justify-content: space-between;
     margin-bottom: 13px;
 
-    >p {
+    > p {
       font-size: 18px;
       font-weight: bold;
     }
 
-    >div {
+    > div {
       width: 38px;
       height: 38px;
       border-radius: 6px;
@@ -319,12 +317,12 @@ main {
     }
   }
 
-  >div {
+  > div {
     flex: 1;
     overflow-y: auto;
 
-    >div {
-      >p {
+    > div {
+      > p {
         margin: 20px 0;
         color: #7f7f7f;
         font-size: 13px;

+ 5 - 6
src/components/picture-upload/BtnImgDownload.vue

@@ -1,17 +1,16 @@
 <template>
-<a-tooltip content="下载">
+  <a-tooltip content="下载">
     <div class="method-button" @click="downloadDocument">
-        <icon-cloud-download />
+      <icon-cloud-download />
     </div>
-</a-tooltip>
+  </a-tooltip>
 </template>
 <script setup>
 const emit = defineEmits(['download']);
 
-const downloadDocument = () => { 
-    emit('download');
+const downloadDocument = () => {
+  emit('download');
 };
-
 </script>
 
 <style lang="scss" scoped>

+ 18 - 25
src/components/picture-upload/FileListTable.vue

@@ -1,45 +1,38 @@
 <template>
-<div>
+  <div>
     <p>
-        <span>已选择图片列表</span>
-        <span>共{{ tableData.length }}个</span>
+      <span>已选择图片列表</span>
+      <span>共{{ tableData.length }}个</span>
     </p>
     <div>
-        <a-table 
-            :pagination="false" 
-            row-key="name" 
-            :columns="columns" 
-            :data="tableData"
-            :selectedKeys="selectedKeys"
-        >
-            <template #methods="{ record }">
-                <BtnImgDownload @download="downloadDocument(record)"/>
-                <BtnImgDelete @delete="deleteDocument"/>
-            </template>
-        </a-table>
+      <a-table :pagination="false" row-key="name" :columns="columns" :data="tableData" :selectedKeys="selectedKeys">
+        <template #methods="{ record }">
+          <BtnImgDownload @download="downloadDocument(record)" />
+          <BtnImgDelete @delete="deleteDocument" />
+        </template>
+      </a-table>
     </div>
-</div>
+  </div>
 </template>
 <script setup>
 import BtnImgDownload from './BtnImgDownload.vue';
 import BtnImgDelete from './BtnImgDelete.vue';
 
 const props = defineProps({
-    tableData: Array,
-    columns: Array,
-    selectedKeys: Array
+  tableData: Array,
+  columns: Array,
+  selectedKeys: Array
 });
 
 const emit = defineEmits(['download', 'delete']);
 
-const downloadDocument = () => { 
-    emit('download');
+const downloadDocument = () => {
+  emit('download');
 };
 
 const deleteDocument = () => {
-    emit('delete');
-}
+  emit('delete');
+};
 </script>
 
-<style lang="scss" scoped>
-</style>
+<style lang="scss" scoped></style>

+ 30 - 30
src/components/use-available-menus.js

@@ -2,47 +2,47 @@ import { watch, ref } from "vue";
 import config from "../utils/config";
 
 export default function useAvailableMenus(props) {
-    const getDisplayMenu = () => {
-        const agent_list = props.agent_list || [];
-        const agent_copy = JSON.parse(JSON.stringify(agent_list));
+  const getDisplayMenu = () => {
+    const agent_list = props.agent_list || [];
+    const agent_copy = JSON.parse(JSON.stringify(agent_list));
 
-        // const agent_config = conf_list;
-        const agent_config = config.slider;
+    // const agent_config = conf_list;
+    const agent_config = config.slider;
 
-        const arr = [];
+    const arr = [];
 
-        const len_conf = agent_config.length;
-        const len_res = agent_copy.length;
+    const len_conf = agent_config.length;
+    const len_res = agent_copy.length;
 
-        for (let i = 0; i < len_conf; i++) {
-            const conf_item = agent_config[i];
+    for (let i = 0; i < len_conf; i++) {
+      const conf_item = agent_config[i];
 
-            let is_exist = false;
-            for (let j = 0; j < len_res; j++) {
-                const res_item = agent_copy[j];
+      let is_exist = false;
+      for (let j = 0; j < len_res; j++) {
+        const res_item = agent_copy[j];
 
-                if (conf_item.title === res_item.name) {
-                    // 已存在
-                    is_exist = true;
-                    break;
-                }
-            }
-
-            if (is_exist) {
-                arr.push(conf_item);
-            }
+        if (conf_item.title === res_item.name) {
+          // 已存在
+          is_exist = true;
+          break;
         }
+      }
+
+      if (is_exist) {
+        arr.push(conf_item);
+      }
+    }
 
-        return arr;
-    };
+    return arr;
+  };
 
-    const diaplay_agents = ref([]);
+  const diaplay_agents = ref([]);
 
-    watch(() => props.agent_list, () => {
-        diaplay_agents.value = getDisplayMenu();
-    });
+  watch(() => props.agent_list, () => {
+    diaplay_agents.value = getDisplayMenu();
+  });
 
-    return diaplay_agents;
+  return diaplay_agents;
 }
 
 

+ 8 - 8
src/main.js

@@ -21,9 +21,9 @@ app.use(ArcoVue);
 app.use(store);
 // app.use(i18n);
 app.provide("$global", {
-    ajax,
-    helper,
-    config
+	ajax,
+	helper,
+	config
 });
 app.directive("outside", outside);
 app.mount("#app");
@@ -32,17 +32,17 @@ document.querySelector("#app").$helper = helper;
 
 // 添加全局方法
 app.config.globalProperties.$messageSuccess = function (data) {
-    this.$message.success(data)
+	this.$message.success(data)
 };
 app.config.globalProperties.$messageWarning = function (data) {
-    this.$message.warning(data)
+	this.$message.warning(data)
 };
 app.config.globalProperties.$messageError = function (data) {
-    this.$message.error(data)
+	this.$message.error(data)
 };
 app.config.globalProperties.$messageInfo = function (data) {
-    this.$message.info(data)
+	this.$message.info(data)
 };
 app.config.globalProperties.$messageNormal = function (data) {
-    this.$message.normal(data)
+	this.$message.normal(data)
 };

+ 19 - 19
src/router/index.js

@@ -2,28 +2,28 @@ import { createRouter, createWebHistory } from "vue-router";
 import Home from "../views/Home.vue";
 
 const router = createRouter({
-    history: createWebHistory(import.meta.env.BASE_URL),
-    routes: [
-        {
-            path: "/",
-            name: "home",
-            component: Home
-        },
-        {
-            path: "/login",
-            name: "login",
-            component: () => import("../views/Login.vue")
-        },
-        {
-            path: "/register",
-            name: "register",
-            component: () => import("../views/Register.vue")
-        },
-    ]
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes: [
+    {
+      path: "/",
+      name: "home",
+      component: Home
+    },
+    {
+      path: "/login",
+      name: "login",
+      component: () => import("../views/Login.vue")
+    },
+    {
+      path: "/register",
+      name: "register",
+      component: () => import("../views/Register.vue")
+    },
+  ]
 });
 
 router.beforeEach((to, from, next) => {
-    next();
+  next();
 });
 
 export default router;

+ 3 - 3
src/store/index.ts

@@ -1,12 +1,12 @@
-import { createPinia } from "pinia";
+import { createPinia } from 'pinia';
 // import useAppStore from "./modules/app";
 // import useUserStore from "./modules/user";
 // import usePinia from "./modules/storeMsg";
 // import useTabBarStore from "./modules/tab-bar";
 // import userModelState from "./modules/shareModel";
-import useImageUploadStatus from "../store/modules/xs-huitu-image-upload/index";
+import useImageUploadStatus from '../store/modules/xs-huitu-image-upload/index';
 
-import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; //引入持久化插件
+import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; //引入持久化插件
 
 const pinia = createPinia();
 

+ 2 - 2
src/store/modules/xs-huitu-image-upload/index.ts

@@ -1,4 +1,4 @@
-import { defineStore } from "pinia";
+import { defineStore } from 'pinia';
 
 /**
  * 在小数绘图的图生文功能中
@@ -15,7 +15,7 @@ import { defineStore } from "pinia";
  *
  * 在上传图片的位置,应检查 img_upload_status 和 msg_send_status 的值,如果 img_upload_status === 1 但是 msg_send_status === 0,则图片上传功能不可用
  */
-const useImageUploadStatus = defineStore("imageUploadStatus", {
+const useImageUploadStatus = defineStore('imageUploadStatus', {
   state: () => ({
     img_upload_status: 0,
     msg_send_status: 0

+ 91 - 91
src/utils/config.js

@@ -1,97 +1,97 @@
 export default {
-    // defaultTitle: "信通小数",
-    // defaultTitle: "上海电科院",
-    defaultTitle: window.__SITE_TITLE,
-    // defaultDesc: "大模型AI能力平台,为你的下一个创意助力",
-    defaultDesc: window.__SITE_INTRODUCE,
-    slider: [
-        {
-            id: 2,
-            title: "知识问答",
-            icon: "5",
-            img: "/src/assets/index/5.png",
-            desc: "遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考",
-            dialog: "垂域知识的问答助手,针对你的提问,我们将遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考。"
-        },
-        {
-            id: 3,
-            title: "文档智能",
-            icon: "7",
-            img: "/src/assets/index/7.png",
-            desc: "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档",
-            dialog: "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档,大小在30M以内。"
-        },
-        {
-            id: 4,
-            title: "智能问答",
-            icon: "1",
-            img: "/src/assets/index/1.png",
-            desc: "能够理解和学习人类的语言,具备多轮对话的能力",
-            dialog: "我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~"
-        },
+  // defaultTitle: "信通小数",
+  // defaultTitle: "上海电科院",
+  defaultTitle: window.__SITE_TITLE,
+  // defaultDesc: "大模型AI能力平台,为你的下一个创意助力",
+  defaultDesc: window.__SITE_INTRODUCE,
+  slider: [
+    {
+      id: 2,
+      title: "知识问答",
+      icon: "5",
+      img: "/src/assets/index/5.png",
+      desc: "遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考",
+      dialog: "垂域知识的问答助手,针对你的提问,我们将遍历已创建的文档知识库,生成完整和准确的答案,同时显示来源文档供您参考。"
+    },
+    {
+      id: 3,
+      title: "文档智能",
+      icon: "7",
+      img: "/src/assets/index/7.png",
+      desc: "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档",
+      dialog: "个人知识库的问答助手,基于您上传的文档进行问答,支持多文档,大小在30M以内。"
+    },
+    {
+      id: 4,
+      title: "智能问答",
+      icon: "1",
+      img: "/src/assets/index/1.png",
+      desc: "能够理解和学习人类的语言,具备多轮对话的能力",
+      dialog: "我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~"
+    },
 
-        {
-            id: 5,
-            title: "智能数据",
-            icon: "8",
-            img: "/src/assets/index/8.png",
-            desc: "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表",
-            dialog: "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表"
-        },
-        {
-            id: 6,
-            title: "小数绘图",
-            icon: "7",
-            img: "/src/assets/index/7.png",
-            desc: "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。",
-            dialog: "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。"
-        },
-        {
-            id: 7,
-            title: "文档出卷",
-            icon: "6",
-            img: "/src/assets/index/6.png",
-            desc: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
-            dialog: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。"
-        },
-        {
-            id: 8,
-            title: "出题组卷",
-            icon: "6",
-            img: "/src/assets/index/6.png",
-            desc: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
-            dialog: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。"
-        },
+    {
+      id: 5,
+      title: "智能数据",
+      icon: "8",
+      img: "/src/assets/index/8.png",
+      desc: "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表",
+      dialog: "您可以上传文档或添加数据库地址,小数可针对你文档的数据进行分析,并生成指定的图表"
+    },
+    {
+      id: 6,
+      title: "小数绘图",
+      icon: "7",
+      img: "/src/assets/index/7.png",
+      desc: "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。",
+      dialog: "基于您上传的图片,生成对应的文字描述并基于图片内容实现问答。"
+    },
+    {
+      id: 7,
+      title: "文档出卷",
+      icon: "6",
+      img: "/src/assets/index/6.png",
+      desc: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
+      dialog: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。"
+    },
+    {
+      id: 8,
+      title: "出题组卷",
+      icon: "6",
+      img: "/src/assets/index/6.png",
+      desc: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。",
+      dialog: "您可以上传文档,小数能针对单文档或多个文档内容自动出题,高效便捷的帮助你建立私人题库。"
+    },
 
-        // {
-        //     id: 0,
-        //     title: "报告生成",
-        //     icon: "2",
-        //     img: "/src/assets/index/2.png",
-        //     // desc: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载",
-        //     desc: "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。",
-        //     // dialog: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载。",
-        //     dialog: "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。"
-        // },
+    // {
+    //     id: 0,
+    //     title: "报告生成",
+    //     icon: "2",
+    //     img: "/src/assets/index/2.png",
+    //     // desc: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载",
+    //     desc: "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。",
+    //     // dialog: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载。",
+    //     dialog: "基于您创建的报告格式和知识库中的文档内容,快速生成定制报告,并支持一键下载。"
+    // },
 
-        {
-            id: 9,
-            title: "文档报告",
-            icon: "2",
-            img: "/src/assets/index/2.png",
-            // desc: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载",
-            desc: '基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。',
-            // dialog: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载。"
-            dialog: '基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。',
-        },
+    {
+      id: 9,
+      title: "文档报告",
+      icon: "2",
+      img: "/src/assets/index/2.png",
+      // desc: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载",
+      desc: '基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。',
+      // dialog: "基于您创建的报告格式和内容,快速生成定制报告,并支持一键下载。"
+      dialog: '基于您创建的报告格式和上传的文档内容,快速生成定制报告,并支持一键下载。',
+    },
 
-        {
-            id: 1,
-            title: "报表合并",
-            icon: "6",
-            img: "/src/assets/index/6.png",
-            desc: "基于您上传的报表进行合并,助您快速完成报表整合与分析",
-            dialog: "基于您上传的报表进行合并,助您快速完成报表整合与分析"
-        },
-    ]
+    {
+      id: 1,
+      title: "报表合并",
+      icon: "6",
+      img: "/src/assets/index/6.png",
+      desc: "基于您上传的报表进行合并,助您快速完成报表整合与分析",
+      dialog: "基于您上传的报表进行合并,助您快速完成报表整合与分析"
+    },
+  ]
 };

+ 103 - 103
src/utils/helper.js

@@ -5,119 +5,119 @@ import * as clipboard from "clipboard-polyfill";
 import ajax from "@/ajax";
 const $bus = mitt();
 const getToken = () => {
-    if (window.localStorage.tokenMap) {
-        const nowTime = new Date().getTime();
-        const result = JSON.parse(window.localStorage.tokenMap);
-        const timeout = result.expiresTime - nowTime;
-        setTimeout(async () => {
-            const refreshData = await ajax.user.refreshToken(result.refreshToken);
-            if (refreshData) {
-                window.localStorage.tokenMap = JSON.stringify(refreshData);
-                getToken();
-            } else {
-                helper.goLink("login");
-                helper.message("error", `请重新登录`);
-            }
-        }, timeout);
-    }
+  if (window.localStorage.tokenMap) {
+    const nowTime = new Date().getTime();
+    const result = JSON.parse(window.localStorage.tokenMap);
+    const timeout = result.expiresTime - nowTime;
+    setTimeout(async () => {
+      const refreshData = await ajax.user.refreshToken(result.refreshToken);
+      if (refreshData) {
+        window.localStorage.tokenMap = JSON.stringify(refreshData);
+        getToken();
+      } else {
+        helper.goLink("login");
+        helper.message("error", `请重新登录`);
+      }
+    }, timeout);
+  }
 };
 const reset = () => {
-    window.localStorage.xintongxiaoshu = "";
+  window.localStorage.xintongxiaoshu = "";
 };
 
 const write = (key, value) => {
-    if (!window.localStorage.xintongxiaoshu) {
-        window.localStorage.xintongxiaoshu = "{}";
-    }
-    const xintongxiaoshu = JSON.parse(window.localStorage.xintongxiaoshu);
-    const data = typeof value === "string" ? value : JSON.stringify(value);
-    xintongxiaoshu[key] = data;
-    window.localStorage.xintongxiaoshu = JSON.stringify(xintongxiaoshu);
+  if (!window.localStorage.xintongxiaoshu) {
+    window.localStorage.xintongxiaoshu = "{}";
+  }
+  const xintongxiaoshu = JSON.parse(window.localStorage.xintongxiaoshu);
+  const data = typeof value === "string" ? value : JSON.stringify(value);
+  xintongxiaoshu[key] = data;
+  window.localStorage.xintongxiaoshu = JSON.stringify(xintongxiaoshu);
 };
 
 const read = (key) => {
-    let result;
-    let data;
-    try {
-        data = JSON.parse(window.localStorage.xintongxiaoshu)[key];
-        result = JSON.parse(data);
-    } catch (e) {
-        result = data || null;
-    }
-    return result;
+  let result;
+  let data;
+  try {
+    data = JSON.parse(window.localStorage.xintongxiaoshu)[key];
+    result = JSON.parse(data);
+  } catch (e) {
+    result = data || null;
+  }
+  return result;
 };
 const helper = (router, ArcoVue) => {
-    return {
-        webSocket: null,
-        read,
-        write,
-        reset,
-        dialogConfig: {
-            isQuestion: false,
-            selectedKeys: [],
-            type: "answer"
-        },
-        $bus,
-        getToken,
-        goLink(path, query = {}) {
-            router.push({ path, query });
-        },
-        copyText(text, content) {
-            clipboard.writeText(text).then(() => {
-                ArcoVue.Message["success"]({ content, duration: 1500 });
-            });
-        },
-        shuffleArray(array) {
-            array.sort(() => Math.random() - 0.5);
-            return array;
-        },
-        goBack() {
-            router.go(-1);
-        },
-        message(type, content) {
-            ArcoVue.Message[type]({ content, duration: 1500 });
-        },
-        setLoading(isLoading = false) {
-            $bus.emit("set-loading", isLoading);
-        },
-        formatSize(size) {
-            if (size < 1024) {
-                return size + "B";
-            } else if (size < 1048576) {
-                return (size / 1024).toFixed(2) + "KB";
-            } else if (size < 1073741824) {
-                return (size / 1048576).toFixed(2) + "MB";
-            } else {
-                return (size / 1073741824).toFixed(2) + "GB";
-            }
-        },
-        getAssetURL(url) {
-            return new URL(url, import.meta.url).href;
-        },
-        setDialog(isInit = false, contentNode, insertCallback = () => { }, closeCallback = () => { }) {
-            if (isInit) {
-                const body = document.getRootNode().body;
-                const div = document.createElement("div");
-                div.id = "all-screen-dialog";
-                div.style = "width:100vw;height:100vh;z-index:9999;position:absolute;top:0";
-                div.append(contentNode);
-                body.append(div);
-                insertCallback();
-                div.addEventListener(
-                    "click",
-                    (e) => {
-                        if (!contentNode.contains(e.target)) {
-                            div.remove();
-                            closeCallback();
-                        }
-                    },
-                    true
-                );
-            } else {
-                const div = document.getElementById("all-screen-dialog");
-                div.remove();
+  return {
+    webSocket: null,
+    read,
+    write,
+    reset,
+    dialogConfig: {
+      isQuestion: false,
+      selectedKeys: [],
+      type: "answer"
+    },
+    $bus,
+    getToken,
+    goLink(path, query = {}) {
+      router.push({ path, query });
+    },
+    copyText(text, content) {
+      clipboard.writeText(text).then(() => {
+        ArcoVue.Message["success"]({ content, duration: 1500 });
+      });
+    },
+    shuffleArray(array) {
+      array.sort(() => Math.random() - 0.5);
+      return array;
+    },
+    goBack() {
+      router.go(-1);
+    },
+    message(type, content) {
+      ArcoVue.Message[type]({ content, duration: 1500 });
+    },
+    setLoading(isLoading = false) {
+      $bus.emit("set-loading", isLoading);
+    },
+    formatSize(size) {
+      if (size < 1024) {
+        return size + "B";
+      } else if (size < 1048576) {
+        return (size / 1024).toFixed(2) + "KB";
+      } else if (size < 1073741824) {
+        return (size / 1048576).toFixed(2) + "MB";
+      } else {
+        return (size / 1073741824).toFixed(2) + "GB";
+      }
+    },
+    getAssetURL(url) {
+      return new URL(url, import.meta.url).href;
+    },
+    setDialog(isInit = false, contentNode, insertCallback = () => { }, closeCallback = () => { }) {
+      if (isInit) {
+        const body = document.getRootNode().body;
+        const div = document.createElement("div");
+        div.id = "all-screen-dialog";
+        div.style = "width:100vw;height:100vh;z-index:9999;position:absolute;top:0";
+        div.append(contentNode);
+        body.append(div);
+        insertCallback();
+        div.addEventListener(
+          "click",
+          (e) => {
+            if (!contentNode.contains(e.target)) {
+              div.remove();
+              closeCallback();
             }
-        }
-    };
+          },
+          true
+        );
+      } else {
+        const div = document.getElementById("all-screen-dialog");
+        div.remove();
+      }
+    }
+  };
 };
 export default helper(router, ArcoVue);

+ 7 - 7
src/views/Analysis.vue

@@ -1,13 +1,13 @@
 <template>
-    <document-cards :hasUpload="true" :hasSlider="false" />
+  <document-cards :hasUpload="true" :hasSlider="false" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {}
+  components: {
+    DocumentCards
+  },
+  setup() {}
 });
 </script>

+ 45 - 45
src/views/Answer.vue

@@ -1,51 +1,51 @@
 <template>
-    <normal-cards :data="data" />
+  <normal-cards :data="data" />
 </template>
 <script>
-import NormalCards from "@/components/NormalCards.vue";
-import { defineComponent, ref } from "vue";
+import NormalCards from '@/components/NormalCards.vue';
+import { defineComponent, ref } from 'vue';
 export default defineComponent({
-    components: { NormalCards },
-    setup() {
-        const data = ref([
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B7.20a5f1df.svg",
-                title: "私人营养师",
-                content: "制定个性化的每日饮食计划,包括早、午、晚餐,确保菜单多样化,满足不同口味。",
-                sug: "请你扮演一个营养师,首次与用户交流时,请你先收集用户的基本情况,得到用户的基础代谢,然后根据此来制定用户每天的早午晚餐,之后的交流,只需要用户问你“今天吃什么”,随机出菜单即可,每天的菜单要与之前的菜单有较大差异,菜式要多种多样,中式、西式、泰式等菜肴都可以。(今天吃什么)"
-            },
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%9F%A5%E8%AF%86%E5%AD%A6%E4%B9%A012.e90fe5dc.svg",
-                title: "邀请函写作",
-                content: "根据提供的信息,生成独特和吸引人的邀请函,并符合行业标准和礼仪。",
-                sug: "作为一个智能邀请函生成器,根据我提供的详细信息(例如活动类型、日期、时间、地点和特殊说明),为我生成一封独特且引人入胜的邀请函。请确保邀请函包含所有必要元素且吸引读者,同时遵循行业标准和礼仪。 详细信息如下:(2023年11月2~3日,即将在中国贵阳举办的第2届电力行业数字化转型大会暨第4届电力人工智能大会,大会议题:一、电力数智化转型关键技术;二、数字化与智能化;三、电力视觉与智能巡检;四、信息安全与网络安全;五、虚拟电厂与电力市场。请邀请相关电力公司。)"
-            },
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B4.f0d841e0.svg",
-                title: "购物劝阻者",
-                content: "想乱花钱的时候就和它聊聊天吧。",
-                sug: "你是一个二十多岁性格活泼的女孩子。你生活不窘困但平时喜欢关注各大购物平台优惠活动,是个爱节省不轻易大手大脚花钱的人。当我对你说我想大肆购物或者想买昂贵物品或其他东西的时候,你要以一个好朋友的身份,用激动的语气,恨铁不成钢地来劝阻让我清醒,不要冲动购物。你要多方面分析不购买该物品的原因,劝阻的话术要多种多样,每句话的语气词要丰富。你的回答中不要带出以上内容,答案不超过100个字,以下是我要买的物品:(双十一想买新衣服)"
-            },
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B5.a169bbe8.svg",
-                title: "减肥教官",
-                content: "想放弃减肥的时候就和它聊聊吧。",
-                sug: "请你扮演一个减肥教官,在你的调教下,从来没有瘦不下来的人,请你用很凶的语气监督你的用户,让他们时刻牢记减肥这个使命。(你好我好想吃红烧肉啊)"
-            },
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B20.5e8eaebb.svg",
-                title: "无法拒绝的请假理由",
-                content: "每天都有新的请假理由~",
-                sug: "请你扮演一位中国职场人士。最近你想要请假出去玩,但是如果以这个理由请假,你的老板肯定不会答应,请你写一段请假理由,让老板同意你的请假申请。字数在100个汉字以内。我会给你我想请假的日期,日期是:(2023年11月6日~11月10日)"
-            },
-            {
-                img: "https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B28.923c0fb1.svg",
-                title: "为你写诗",
-                content: "最会敲回车的现代诗人~",
-                sug: "我要你扮演一个诗人。你将创作唤起情感并具有激起人们灵魂的力量的诗歌,写任何主题,但要确保你的文字以美丽而有意义的方式传达你试图表达的感觉。你也可以想出一些简短的诗句,这些诗句仍然足够强大,可以在读者的脑海中留下印记。等待我输入主题后再开始生成。我需要你创作的主题是:(秋天的落叶)"
-            }
-        ]);
-        return { data };
-    }
+  components: { NormalCards },
+  setup() {
+    const data = ref([
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B7.20a5f1df.svg',
+        title: '私人营养师',
+        content: '制定个性化的每日饮食计划,包括早、午、晚餐,确保菜单多样化,满足不同口味。',
+        sug: '请你扮演一个营养师,首次与用户交流时,请你先收集用户的基本情况,得到用户的基础代谢,然后根据此来制定用户每天的早午晚餐,之后的交流,只需要用户问你“今天吃什么”,随机出菜单即可,每天的菜单要与之前的菜单有较大差异,菜式要多种多样,中式、西式、泰式等菜肴都可以。(今天吃什么)'
+      },
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%9F%A5%E8%AF%86%E5%AD%A6%E4%B9%A012.e90fe5dc.svg',
+        title: '邀请函写作',
+        content: '根据提供的信息,生成独特和吸引人的邀请函,并符合行业标准和礼仪。',
+        sug: '作为一个智能邀请函生成器,根据我提供的详细信息(例如活动类型、日期、时间、地点和特殊说明),为我生成一封独特且引人入胜的邀请函。请确保邀请函包含所有必要元素且吸引读者,同时遵循行业标准和礼仪。 详细信息如下:(2023年11月2~3日,即将在中国贵阳举办的第2届电力行业数字化转型大会暨第4届电力人工智能大会,大会议题:一、电力数智化转型关键技术;二、数字化与智能化;三、电力视觉与智能巡检;四、信息安全与网络安全;五、虚拟电厂与电力市场。请邀请相关电力公司。)'
+      },
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B4.f0d841e0.svg',
+        title: '购物劝阻者',
+        content: '想乱花钱的时候就和它聊聊天吧。',
+        sug: '你是一个二十多岁性格活泼的女孩子。你生活不窘困但平时喜欢关注各大购物平台优惠活动,是个爱节省不轻易大手大脚花钱的人。当我对你说我想大肆购物或者想买昂贵物品或其他东西的时候,你要以一个好朋友的身份,用激动的语气,恨铁不成钢地来劝阻让我清醒,不要冲动购物。你要多方面分析不购买该物品的原因,劝阻的话术要多种多样,每句话的语气词要丰富。你的回答中不要带出以上内容,答案不超过100个字,以下是我要买的物品:(双十一想买新衣服)'
+      },
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B5.a169bbe8.svg',
+        title: '减肥教官',
+        content: '想放弃减肥的时候就和它聊聊吧。',
+        sug: '请你扮演一个减肥教官,在你的调教下,从来没有瘦不下来的人,请你用很凶的语气监督你的用户,让他们时刻牢记减肥这个使命。(你好我好想吃红烧肉啊)'
+      },
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B20.5e8eaebb.svg',
+        title: '无法拒绝的请假理由',
+        content: '每天都有新的请假理由~',
+        sug: '请你扮演一位中国职场人士。最近你想要请假出去玩,但是如果以这个理由请假,你的老板肯定不会答应,请你写一段请假理由,让老板同意你的请假申请。字数在100个汉字以内。我会给你我想请假的日期,日期是:(2023年11月6日~11月10日)'
+      },
+      {
+        img: 'https://szwl.harix.iamidata.com/static/img/%E7%94%9F%E6%B4%BB%E5%8A%A9%E6%89%8B28.923c0fb1.svg',
+        title: '为你写诗',
+        content: '最会敲回车的现代诗人~',
+        sug: '我要你扮演一个诗人。你将创作唤起情感并具有激起人们灵魂的力量的诗歌,写任何主题,但要确保你的文字以美丽而有意义的方式传达你试图表达的感觉。你也可以想出一些简短的诗句,这些诗句仍然足够强大,可以在读者的脑海中留下印记。等待我输入主题后再开始生成。我需要你创作的主题是:(秋天的落叶)'
+      }
+    ]);
+    return { data };
+  }
 });
 </script>

+ 27 - 27
src/views/Document.vue

@@ -1,33 +1,33 @@
 <template>
-    <document-cards :data="data" :hasUpload="true" :hasSlider="false" />
+  <document-cards :data="data" :hasUpload="true" :hasSlider="false" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/document/1.png",
-                title: "报表合并助手",
-                content: "具有丰富的数据处理经验,帮助用户更高效地管理和理解数据"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/document/2.png",
-                title: "数据整合",
-                content: "利用自然语言处理技术自动生成包含汇总数据和分析的“大表” "
-            }
-        ]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  setup() {
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/document/1.png',
+        title: '报表合并助手',
+        content: '具有丰富的数据处理经验,帮助用户更高效地管理和理解数据'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/document/2.png',
+        title: '数据整合',
+        content: '利用自然语言处理技术自动生成包含汇总数据和分析的“大表” '
+      }
+    ]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 28 - 28
src/views/DocumentAnswer.vue

@@ -1,34 +1,34 @@
 <template>
-    <document-cards :hasUpload="false" :uploadFile="true" :data="data" :hasSlider="false" :agentId="agentId" />
+  <document-cards :hasUpload="false" :uploadFile="true" :data="data" :hasSlider="false" :agentId="agentId" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    props: ["agentId"],
-    setup() {
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/answer/1-1.png",
-                title: "自定义个人文档",
-                content: "支持个人文档上传,以列表形式管理个人文档库"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/answer/1-2.png",
-                title: "多文档问答",
-                content: "支持勾选多个文档,实现基于限定文档的问答"
-            },
-        ]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  props: ['agentId'],
+  setup() {
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/answer/1-1.png',
+        title: '自定义个人文档',
+        content: '支持个人文档上传,以列表形式管理个人文档库'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/answer/1-2.png',
+        title: '多文档问答',
+        content: '支持勾选多个文档,实现基于限定文档的问答'
+      }
+    ]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 12 - 12
src/views/DocumentCombine.vue

@@ -1,18 +1,18 @@
 <template>
-    <document-cards :data="data" :hasUpload="false" :hasSlider="false" />
+  <document-cards :data="data" :hasUpload="false" :hasSlider="false" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {
-        const data = ref([]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  setup() {
+    const data = ref([]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 269 - 254
src/views/DocumentDetail.vue

@@ -1,293 +1,308 @@
 <template>
-    <main>
-        <div class="left">
-            <header>
-                <div @click="goBack"><icon-left style="margin-right: 5px" />返回知识问答</div>
-            </header>
-            <div>
-                <div style="background-color: rgb(255, 110, 110)">{{ userName?.slice(0, 1) }}</div>
-                <p>{{ targetDocument.question }}</p>
+  <main>
+    <div class="left">
+      <header>
+        <div @click="goBack"><icon-left style="margin-right: 5px" />返回知识问答</div>
+      </header>
+      <div>
+        <div style="background-color: rgb(255, 110, 110)">{{ userName?.slice(0, 1) }}</div>
+        <p>{{ targetDocument.question }}</p>
+      </div>
+      <p>
+        <span>以下是根据您的提问搜索到的相关文档</span>
+        <span>共 {{ list.length }} 条</span>
+      </p>
+      <section>
+        <div
+          :class="[item.doc_id === target_doc_id ? 'activeBox' : '']"
+          v-for="(item, key) in list"
+          :key="key"
+          @click="handelChangePdf(item)"
+        >
+          <div>
+            <img src="@/assets/document/icon.svg" />
+          </div>
+          <div>
+            <p>{{ item.doc_name }}</p>
+            <p>{{ item.desc }}</p>
+            <span>
+              <b>检索片段</b>
+              <em></em>
+            </span>
+            <div
+              :class="[frag.chunk_id === target_chunk_id ? 'activeLink' : '']"
+              v-for="(frag, index) in item.fragments"
+              :key="index"
+              @click.stop="handlerClickFragment(frag)"
+            >
+              <span>{{ index + 1 }}.</span>
+              {{ frag.content_with_weight }}
             </div>
-            <p>
-                <span>以下是根据您的提问搜索到的相关文档</span>
-                <span>共 {{ list.length }} 条</span>
-            </p>
-            <section>
-                <div :class="[item.doc_id === target_doc_id? 'activeBox' : '']"
-                    v-for="(item, key) in list" :key="key" @click="handelChangePdf(item)">
-                    <div>
-                        <img src="@/assets/document/icon.svg" />
-                    </div>
-                    <div>
-                        <p>{{ item.doc_name }}</p>
-                        <p>{{ item.desc }}</p>
-                        <span>
-                            <b>检索片段</b>
-                            <em></em>
-                        </span>
-                        <div :class="[frag.chunk_id === target_chunk_id? 'activeLink' : '']"
-                            v-for="(frag, index) in item.fragments" :key="index" @click.stop="handlerClickFragment(frag)">
-                            <span>{{ index + 1 }}.</span>
-                            {{ frag.content_with_weight }}
-                        </div>
-                    </div>
-                </div>
-            </section>
+          </div>
         </div>
-        <div class="right" ref="pdfFather">
-            <PDFViewer v-if="showPdfViewer" ref="pdfViewer" class="pdf-viewer" :url="pdf_url" :doc_width="DOC_WIDTH" :positions="positions">
-            </PDFViewer>
-        </div>
-    </main>
+      </section>
+    </div>
+    <div class="right" ref="pdfFather">
+      <PDFViewer
+        v-if="showPdfViewer"
+        ref="pdfViewer"
+        class="pdf-viewer"
+        :url="pdf_url"
+        :doc_width="DOC_WIDTH"
+        :positions="positions"
+      >
+      </PDFViewer>
+    </div>
+  </main>
 </template>
 <script>
-import { defineComponent, inject, onMounted, ref, nextTick } from "vue";
-import PDFViewer from '@/components/pdf-viewer/PDFViewer.vue'
+import { defineComponent, inject, onMounted, ref, nextTick } from 'vue';
+import PDFViewer from '@/components/pdf-viewer/PDFViewer.vue';
 import { getDocumentUrl } from '@/ajax/document';
 export default defineComponent({
-    props: ['targetDocument', 'dialogList'],
-    components: { PDFViewer },
-    setup(props, { emit }) {
-        const { helper, config } = inject("$global");
-        const userName = ref(helper.read("userName") || "");
-        const list = ref([]);
-        const showPdfViewer = ref(true);
-        const positions = ref([]);
-        const pdfFather = ref(null);
-        const DOC_WIDTH = ref(1100)
-        const pdf_url = ref('')
-        let target_doc_id = ref(props.targetDocument.id)
-        let target_chunk_id = ref('')
-        pdf_url.value = getDocumentUrl(target_doc_id.value);
-        const pdfViewer = ref(null);
-        const docData = props.targetDocument
-        list.value = docData.doc_aggs.map(item => {
-            return {
-                ...item,
-                fragments: docData.chunks.filter(chunk => chunk.docnm_kwd === item.doc_name),
-                desc: docData.chunks.filter(chunk => chunk.docnm_kwd === item.doc_name)[0]?.content_ltks
-            }
-        })
-        const goBack = () => {
-            emit("go-back");
-        };
-        const handelChangePdf = (item) => {
-            if (item.doc_id !== target_doc_id.value) {
-                pdf_url.value = getDocumentUrl(item.doc_id)
-                target_doc_id.value = item.doc_id
-                target_chunk_id.value = ''
-                readLoadPdf()
-            }
-        }
-        const handlerClickFragment = (frag) => {
-            target_chunk_id.value = frag.chunk_id
-            if (frag.doc_id !== target_doc_id.value) {
-                pdf_url.value = getDocumentUrl(frag.doc_id)
-                target_doc_id.value = frag.doc_id
-                readLoadPdf()
-            }
-            positions.value = [...frag.positions] || [];
-            if (frag.positions && frag.positions.length) {
-                pdfViewer.value.toPageIndex(positions.value[0][0], positions.value)
-            }
-        }
-        // 切换问答需要重新加载pdf
-        const readLoadPdf = () => {
-            positions.value = []
-            showPdfViewer.value = false
-            setTimeout(() => {
-                showPdfViewer.value = true
-            })
-        }
-        onMounted(() => {
-            DOC_WIDTH.value = pdfFather.value.getBoundingClientRect().width
-        })
-        return {
-            list,
-            goBack,
-            pdf_url,
-            DOC_WIDTH,
-            userName,
-            positions,
-            pdfFather,
-            pdfViewer,
-            showPdfViewer,
-            target_doc_id,
-            target_chunk_id,
-            handelChangePdf,
-            handlerClickFragment
-        };
-    }
+  props: ['targetDocument', 'dialogList'],
+  components: { PDFViewer },
+  setup(props, { emit }) {
+    const { helper, config } = inject('$global');
+    const userName = ref(helper.read('userName') || '');
+    const list = ref([]);
+    const showPdfViewer = ref(true);
+    const positions = ref([]);
+    const pdfFather = ref(null);
+    const DOC_WIDTH = ref(1100);
+    const pdf_url = ref('');
+    let target_doc_id = ref(props.targetDocument.id);
+    let target_chunk_id = ref('');
+    pdf_url.value = getDocumentUrl(target_doc_id.value);
+    const pdfViewer = ref(null);
+    const docData = props.targetDocument;
+    list.value = docData.doc_aggs.map((item) => {
+      return {
+        ...item,
+        fragments: docData.chunks.filter((chunk) => chunk.docnm_kwd === item.doc_name),
+        desc: docData.chunks.filter((chunk) => chunk.docnm_kwd === item.doc_name)[0]?.content_ltks
+      };
+    });
+    const goBack = () => {
+      emit('go-back');
+    };
+    const handelChangePdf = (item) => {
+      if (item.doc_id !== target_doc_id.value) {
+        pdf_url.value = getDocumentUrl(item.doc_id);
+        target_doc_id.value = item.doc_id;
+        target_chunk_id.value = '';
+        readLoadPdf();
+      }
+    };
+    const handlerClickFragment = (frag) => {
+      target_chunk_id.value = frag.chunk_id;
+      if (frag.doc_id !== target_doc_id.value) {
+        pdf_url.value = getDocumentUrl(frag.doc_id);
+        target_doc_id.value = frag.doc_id;
+        readLoadPdf();
+      }
+      positions.value = [...frag.positions] || [];
+      if (frag.positions && frag.positions.length) {
+        pdfViewer.value.toPageIndex(positions.value[0][0], positions.value);
+      }
+    };
+    // 切换问答需要重新加载pdf
+    const readLoadPdf = () => {
+      positions.value = [];
+      showPdfViewer.value = false;
+      setTimeout(() => {
+        showPdfViewer.value = true;
+      });
+    };
+    onMounted(() => {
+      DOC_WIDTH.value = pdfFather.value.getBoundingClientRect().width;
+    });
+    return {
+      list,
+      goBack,
+      pdf_url,
+      DOC_WIDTH,
+      userName,
+      positions,
+      pdfFather,
+      pdfViewer,
+      showPdfViewer,
+      target_doc_id,
+      target_chunk_id,
+      handelChangePdf,
+      handlerClickFragment
+    };
+  }
 });
 </script>
 <style lang="scss" scoped>
 main {
-    display: flex;
-    height: 100%;
+  display: flex;
+  height: 100%;
 
-    >div {
-        height: 100%;
+  > div {
+    height: 100%;
 
-        &.right {
-            flex: 1;
-            width: calc(100% - 460px);
-            position: relative;
+    &.right {
+      flex: 1;
+      width: calc(100% - 460px);
+      position: relative;
 
-            .pdf-viewer {
-                width: 100%;
-            }
-        }
+      .pdf-viewer {
+        width: 100%;
+      }
+    }
 
-        &.left {
-            width: 460px;
-            padding: 20px 0 20px 20px;
-            background: #e2e4eb;
-            display: flex;
-            flex-direction: column;
+    &.left {
+      width: 460px;
+      padding: 20px 0 20px 20px;
+      background: #e2e4eb;
+      display: flex;
+      flex-direction: column;
 
-            >header {
-                padding-right: 20px;
-                margin-bottom: 10px;
+      > header {
+        padding-right: 20px;
+        margin-bottom: 10px;
 
-                >div {
-                    cursor: pointer;
-                    font-weight: bold;
+        > div {
+          cursor: pointer;
+          font-weight: bold;
 
-                    &:hover {
-                        color: #00aea3;
-                    }
-                }
-            }
+          &:hover {
+            color: #00aea3;
+          }
+        }
+      }
 
-            >div {
-                display: flex;
-                gap: 20px;
-                padding: 20px 20px 20px 0;
+      > div {
+        display: flex;
+        gap: 20px;
+        padding: 20px 20px 20px 0;
 
-                >div {
-                    width: 40px;
-                    height: 40px;
-                    border-radius: 20px;
-                    display: flex;
-                    align-items: center;
-                    justify-content: center;
-                    color: #fff;
-                }
+        > div {
+          width: 40px;
+          height: 40px;
+          border-radius: 20px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          color: #fff;
+        }
 
-                >p {
-                    background: #f6f8ff;
-                    border-radius: 0 12px 12px 12px;
-                    padding: 16px 16px;
-                    font-size: 16px;
-                    line-height: 1.6;
-                }
-            }
+        > p {
+          background: #f6f8ff;
+          border-radius: 0 12px 12px 12px;
+          padding: 16px 16px;
+          font-size: 16px;
+          line-height: 1.6;
+        }
+      }
 
-            >p {
-                display: flex;
-                justify-content: space-between;
-                color: #727376;
-                margin-bottom: 20px;
-                padding-right: 20px;
-            }
+      > p {
+        display: flex;
+        justify-content: space-between;
+        color: #727376;
+        margin-bottom: 20px;
+        padding-right: 20px;
+      }
 
-            >section {
-                flex: 1;
-                overflow-y: auto;
-                padding-right: 20px;
+      > section {
+        flex: 1;
+        overflow-y: auto;
+        padding-right: 20px;
 
-                >div {
-                    background: #fff;
-                    border-radius: 8px;
-                    padding: 12px;
-                    margin-bottom: 16px;
-                    cursor: pointer;
-                    gap: 5px;
-                    display: flex;
-                    border: 2px solid transparent;
+        > div {
+          background: #fff;
+          border-radius: 8px;
+          padding: 12px;
+          margin-bottom: 16px;
+          cursor: pointer;
+          gap: 5px;
+          display: flex;
+          border: 2px solid transparent;
 
-                    &:hover,
-                    &.active {
-                        border: 2px solid #00aea3;
-                    }
+          &:hover,
+          &.active {
+            border: 2px solid #00aea3;
+          }
 
-                    >div {
-                        >img {
-                            margin-top: 5px;
-                        }
+          > div {
+            > img {
+              margin-top: 5px;
+            }
 
-                        >p {
-                            &:nth-child(1) {
-                                font-size: 16px;
-                                line-height: 28px;
-                                font-weight: bold;
-                                overflow: hidden;
-                                text-overflow: ellipsis;
-                                display: -webkit-box;
-                                -webkit-box-orient: vertical;
-                                -webkit-line-clamp: 2;
-                                margin-bottom: 8px;
-                            }
+            > p {
+              &:nth-child(1) {
+                font-size: 16px;
+                line-height: 28px;
+                font-weight: bold;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                display: -webkit-box;
+                -webkit-box-orient: vertical;
+                -webkit-line-clamp: 2;
+                margin-bottom: 8px;
+              }
 
-                            &:nth-child(2) {
-                                font-size: 16px;
-                                line-height: 28px;
-                                overflow: hidden;
-                                text-overflow: ellipsis;
-                                display: -webkit-box;
-                                -webkit-box-orient: vertical;
-                                -webkit-line-clamp: 3;
-                            }
-                        }
+              &:nth-child(2) {
+                font-size: 16px;
+                line-height: 28px;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                display: -webkit-box;
+                -webkit-box-orient: vertical;
+                -webkit-line-clamp: 3;
+              }
+            }
 
-                        >span {
-                            display: flex;
-                            align-items: center;
-                            gap: 12px;
-                            margin: 12px 0;
+            > span {
+              display: flex;
+              align-items: center;
+              gap: 12px;
+              margin: 12px 0;
 
-                            >b {
-                                font-style: normal;
-                                color: #aaa;
-                                font-size: 13px;
-                            }
+              > b {
+                font-style: normal;
+                color: #aaa;
+                font-size: 13px;
+              }
 
-                            >em {
-                                flex: 1;
-                                height: 1px;
-                                background: #e3e3e3;
-                            }
-                        }
+              > em {
+                flex: 1;
+                height: 1px;
+                background: #e3e3e3;
+              }
+            }
 
-                        >div {
-                            overflow: hidden;
-                            white-space: nowrap;
-                            text-overflow: ellipsis;
-                            margin-bottom: 10px;
-                            font-size: 13px;
-                            line-height: 18px;
-                            width: 300px;
-                            cursor: pointer;
+            > div {
+              overflow: hidden;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+              margin-bottom: 10px;
+              font-size: 13px;
+              line-height: 18px;
+              width: 300px;
+              cursor: pointer;
 
-                            &:hover,
-                            &.active {
-                                color: #00aea3;
-                            }
+              &:hover,
+              &.active {
+                color: #00aea3;
+              }
 
-                            span {
-                                margin-right: 5px;
-                            }
-                        }
-                    }
-                }
+              span {
+                margin-right: 5px;
+              }
             }
+          }
         }
+      }
     }
-    .activeBox{
-        border: 3px solid #00aea3 !important;
-    }
-    .activeLink {
-        color: #00aea3 !important;
-    }
+  }
+  .activeBox {
+    border: 3px solid #00aea3 !important;
+  }
+  .activeLink {
+    color: #00aea3 !important;
+  }
 }
 </style>

+ 41 - 41
src/views/DocumentInterlocution.vue

@@ -1,47 +1,47 @@
 <template>
-    <document-cards :data="data" :hasUpload="false" :hasSlider="false" :isQuestion="true" />
+  <document-cards :data="data" :hasUpload="false" :hasSlider="false" :isQuestion="true" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/answer/1.png",
-                title: "多源多问答",
-                content: "检索多个文档内容,通过大模型生成答案"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/answer/2.png",
-                title: "垂域知识库",
-                content: "通过后台管理平台,快速构建垂域的专业知识库"
-            },
-            {
-                background: "rgba(24, 200, 138, 0.06)",
-                color: "rgb(24, 200, 138)",
-                img: "/src/assets/answer/3.png",
-                title: "文档溯源",
-                content: "答案引用的文档支持预览及文档内容高亮"
-            },
-            {
-                background: "rgba(255, 110, 110, 0.06)",
-                color: "rgb(255, 110, 110)",
-                img: "/src/assets/answer/4.png",
-                title: "文档检索",
-                content: "支持用户查看问题相关的全量文档"
-            }
-        ]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  setup() {
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/answer/1.png',
+        title: '多源多问答',
+        content: '检索多个文档内容,通过大模型生成答案'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/answer/2.png',
+        title: '垂域知识库',
+        content: '通过后台管理平台,快速构建垂域的专业知识库'
+      },
+      {
+        background: 'rgba(24, 200, 138, 0.06)',
+        color: 'rgb(24, 200, 138)',
+        img: '/src/assets/answer/3.png',
+        title: '文档溯源',
+        content: '答案引用的文档支持预览及文档内容高亮'
+      },
+      {
+        background: 'rgba(255, 110, 110, 0.06)',
+        color: 'rgb(255, 110, 110)',
+        img: '/src/assets/answer/4.png',
+        title: '文档检索',
+        content: '支持用户查看问题相关的全量文档'
+      }
+    ]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 27 - 27
src/views/DocumentQuestion.vue

@@ -1,33 +1,33 @@
 <template>
-    <document-cards :data="data" :hasUpload="false" :isQuestion="true" />
+  <document-cards :data="data" :hasUpload="false" :isQuestion="true" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/answer/1.png",
-                title: "多类型题目",
-                content: "支持生成单选、多选、判断、问答题等多种题目类型"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/answer/2.png",
-                title: "文档管理",
-                content: "支持生成单选、多选、判断、问答题等多种题目类型"
-            },
-        ]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  setup() {
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/answer/1.png',
+        title: '多类型题目',
+        content: '支持生成单选、多选、判断、问答题等多种题目类型'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/answer/2.png',
+        title: '文档管理',
+        content: '支持生成单选、多选、判断、问答题等多种题目类型'
+      }
+    ]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 27 - 27
src/views/DocumentQuestion2.vue

@@ -1,33 +1,33 @@
 <template>
-    <document-cards :data="data" :hasUpload="false" :isQuestion="true" />
+  <document-cards :data="data" :hasUpload="false" :isQuestion="true" />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    setup() {
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/answer/1.png",
-                title: "多类型题目",
-                content: "支持生成单选、多选、判断、问答题等多种题目类型"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/answer/2.png",
-                title: "文档管理",
-                content: "支持生成单选、多选、判断、问答题等多种题目类型"
-            },
-        ]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  setup() {
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/answer/1.png',
+        title: '多类型题目',
+        content: '支持生成单选、多选、判断、问答题等多种题目类型'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/answer/2.png',
+        title: '文档管理',
+        content: '支持生成单选、多选、判断、问答题等多种题目类型'
+      }
+    ]);
+    return {
+      data
+    };
+  }
 });
 </script>

+ 20 - 14
src/views/DocumentsmartData.vue

@@ -1,20 +1,26 @@
 <template>
-    <document-cards :hasUpload="true" :uploadFile="true" :data="data" :hasSlider="false" :agentId="agentId"
-        :agengtName="'智能数据'" />
+  <document-cards
+    :hasUpload="true"
+    :uploadFile="true"
+    :data="data"
+    :hasSlider="false"
+    :agentId="agentId"
+    :agengtName="'智能数据'"
+  />
 </template>
 <script>
-import DocumentCards from "@/components/DocumentCards.vue";
-import { defineComponent, ref, inject, reactive } from "vue";
+import DocumentCards from '@/components/DocumentCards.vue';
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        DocumentCards
-    },
-    props: ["agentId"],
-    setup() {
-        const data = ref([]);
-        return {
-            data
-        };
-    }
+  components: {
+    DocumentCards
+  },
+  props: ['agentId'],
+  setup() {
+    const data = ref([]);
+    return {
+      data
+    };
+  }
 });
 </script>

ファイルの差分が大きいため隠しています
+ 527 - 481
src/views/Home.vue


+ 206 - 197
src/views/Index.vue

@@ -1,227 +1,236 @@
 <template>
-    <main>
-        <div class="bg">
-            <img src="@/assets/index/bg.gif" />
-            <img src="@/assets/index/bg.png" />
+  <main>
+    <div class="bg">
+      <img src="@/assets/index/bg.gif" />
+      <img src="@/assets/index/bg.png" />
+    </div>
+    <section>
+      <header>
+        <p>
+          欢迎使用<b>{{ title }}</b>
+        </p>
+        <div>{{ desc }}</div>
+      </header>
+
+      <div class="swiper-main" v-if="diaplay_agents.length !== 0">
+        <div :class="{ prev: true, disabled: page === 0 }" @click="goPrev">
+          <icon-left />
         </div>
-        <section>
-            <header>
-                <p>
-                    欢迎使用<b>{{ title }}</b>
-                </p>
-                <div>{{ desc }}</div>
-            </header>
-
-            <div class="swiper-main" v-if="diaplay_agents.length !== 0">
-                <div :class="{ prev: true, disabled: page === 0 }" @click="goPrev">
-                    <icon-left />
-                </div>
-                <swiper class="the-swiper-wrap" :slides-per-group="number" :slides-per-view="number" :space-between="10"
-                    @swiper="onSwiper">
-                    <swiper-slide v-for="item in diaplay_agents" :key="item.id" width="230">
-                        <div class="swiper-item" @mouseover="onMouseover(item.id)" @mouseleave="onMouseleave"
-                            @click="handleClick(item.id, item.title)">
-                            <div>
-                                <img :src="getAssetURL(item.img)" width="48" />
-                                <p>{{ item.title }}</p>
-                            </div>
-                        </div>
-                    </swiper-slide>
-                </swiper>
-                <div :class="{ next: true, disabled: page === pages - 1 }" @click="goNext">
-                    <icon-right />
-                </div>
+        <swiper
+          class="the-swiper-wrap"
+          :slides-per-group="number"
+          :slides-per-view="number"
+          :space-between="10"
+          @swiper="onSwiper"
+        >
+          <swiper-slide v-for="item in diaplay_agents" :key="item.id" width="230">
+            <div
+              class="swiper-item"
+              @mouseover="onMouseover(item.id)"
+              @mouseleave="onMouseleave"
+              @click="handleClick(item.id, item.title)"
+            >
+              <div>
+                <img :src="getAssetURL(item.img)" width="48" />
+                <p>{{ item.title }}</p>
+              </div>
             </div>
-        </section>
-    </main>
+          </swiper-slide>
+        </swiper>
+        <div :class="{ next: true, disabled: page === pages - 1 }" @click="goNext">
+          <icon-right />
+        </div>
+      </div>
+    </section>
+  </main>
 </template>
 
 <script>
-import { defineComponent, inject, onMounted, ref, watch, } from "vue";
-import { Swiper, SwiperSlide } from "swiper/vue";
-import "swiper/css";
+import { defineComponent, inject, onMounted, ref, watch } from 'vue';
+import { Swiper, SwiperSlide } from 'swiper/vue';
+import 'swiper/css';
 
 import useAvailableMenus from '../components/use-available-menus';
 
 export default defineComponent({
-    props: ["number", 'agent_list'],
-    components: {
-        Swiper,
-        SwiperSlide
-    },
-    setup(props, { emit }) {
-        const { helper, config } = inject("$global");
-        let useSwiper = null;
-        let page = ref(0);
-        const title = ref(config.defaultTitle);
-        const desc = ref(config.defaultDesc);
-        const pages = ref(Math.ceil(config.slider.length / props.number));
-        const onSwiper = (swiper) => {
-            useSwiper = swiper;
-        };
-        const goNext = () => {
-            if (page.value === pages.value - 1) return;
-            page.value += 1;
-            useSwiper.slideTo(props.number * page.value);
-        };
-        const goPrev = () => {
-            if (page.value === 0) return;
-            page.value -= 1;
-            useSwiper.slideTo(props.number * page.value);
-        };
-        const onMouseover = (key) => {
-            title.value = config.slider.find((item) => item.id === key).title;
-            desc.value = config.slider.find((item) => item.id === key).desc;
-        };
-        const onMouseleave = () => {
-            title.value = config.defaultTitle;
-            desc.value = config.defaultDesc;
-        };
-        const handleClick = (id, title) => {
-            emit("select-nav", { id, title });
-        };
-
-        const diaplay_agents = useAvailableMenus(props);
-
-        return {
-            onSwiper,
-            getAssetURL: helper.getAssetURL,
-
-            slider: config.slider,
-            diaplay_agents: diaplay_agents,
-
-            goNext,
-            goPrev,
-            page,
-            pages,
-            onMouseover,
-            onMouseleave,
-            title,
-            desc,
-            handleClick
-        };
-    }
+  props: ['number', 'agent_list'],
+  components: {
+    Swiper,
+    SwiperSlide
+  },
+  setup(props, { emit }) {
+    const { helper, config } = inject('$global');
+    let useSwiper = null;
+    let page = ref(0);
+    const title = ref(config.defaultTitle);
+    const desc = ref(config.defaultDesc);
+    const pages = ref(Math.ceil(config.slider.length / props.number));
+    const onSwiper = (swiper) => {
+      useSwiper = swiper;
+    };
+    const goNext = () => {
+      if (page.value === pages.value - 1) return;
+      page.value += 1;
+      useSwiper.slideTo(props.number * page.value);
+    };
+    const goPrev = () => {
+      if (page.value === 0) return;
+      page.value -= 1;
+      useSwiper.slideTo(props.number * page.value);
+    };
+    const onMouseover = (key) => {
+      title.value = config.slider.find((item) => item.id === key).title;
+      desc.value = config.slider.find((item) => item.id === key).desc;
+    };
+    const onMouseleave = () => {
+      title.value = config.defaultTitle;
+      desc.value = config.defaultDesc;
+    };
+    const handleClick = (id, title) => {
+      emit('select-nav', { id, title });
+    };
+
+    const diaplay_agents = useAvailableMenus(props);
+
+    return {
+      onSwiper,
+      getAssetURL: helper.getAssetURL,
+
+      slider: config.slider,
+      diaplay_agents: diaplay_agents,
+
+      goNext,
+      goPrev,
+      page,
+      pages,
+      onMouseover,
+      onMouseleave,
+      title,
+      desc,
+      handleClick
+    };
+  }
 });
 </script>
 <style lang="scss" scoped>
 main {
-    width: 100%;
-    height: 100%;
-    position: relative;
-    overflow: hidden;
+  width: 100%;
+  height: 100%;
+  position: relative;
+  overflow: hidden;
 
-    >section {
-        padding-top: 67px;
-        position: relative;
-        z-index: 2;
-        margin: 0 auto;
-        width: 85%;
-
-        >header {
-            text-align: center;
-            color: #fff;
-
-            >p {
-                font-size: 40px;
-            }
+  > section {
+    padding-top: 67px;
+    position: relative;
+    z-index: 2;
+    margin: 0 auto;
+    width: 85%;
+
+    > header {
+      text-align: center;
+      color: #fff;
+
+      > p {
+        font-size: 40px;
+      }
+
+      > div {
+        margin-top: 10px;
+        font-size: 20px;
+      }
+    }
 
-            >div {
-                margin-top: 10px;
-                font-size: 20px;
-            }
+    .swiper-main {
+      position: relative;
+      height: 90px;
+      margin-top: 40px;
+
+      .prev,
+      .next {
+        position: absolute;
+        width: 40px;
+        height: 40px;
+        border-radius: 20px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background: #fff;
+        top: 25px;
+        cursor: pointer;
+
+        &:hover {
+          opacity: 0.8;
         }
 
-        .swiper-main {
-            position: relative;
-            height: 90px;
-            margin-top: 40px;
-
-            .prev,
-            .next {
-                position: absolute;
-                width: 40px;
-                height: 40px;
-                border-radius: 20px;
-                display: flex;
-                justify-content: center;
-                align-items: center;
-                background: #fff;
-                top: 25px;
-                cursor: pointer;
-
-                &:hover {
-                    opacity: 0.8;
-                }
-
-                &.disabled {
-                    cursor: not-allowed;
-
-                    &:hover {
-                        opacity: 1;
-                    }
-                }
-            }
+        &.disabled {
+          cursor: not-allowed;
 
-            .prev {
-                left: -20px;
+          &:hover {
+            opacity: 1;
+          }
+        }
+      }
+
+      .prev {
+        left: -20px;
+      }
+
+      .next {
+        right: -20px;
+      }
+
+      .the-swiper-wrap {
+        position: absolute;
+        top: 0;
+        left: 30px;
+        right: 30px;
+        overflow: hidden;
+
+        .swiper-item {
+          width: 230px;
+          height: 90px;
+          background: #fff;
+          border-radius: 12px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          cursor: pointer;
+
+          &:hover {
+            background: #00aea3;
+
+            > div > p {
+              color: #fff;
             }
+          }
 
-            .next {
-                right: -20px;
-            }
+          > div {
+            display: flex;
+            align-items: center;
 
-            .the-swiper-wrap {
-                position: absolute;
-                top: 0;
-                left: 30px;
-                right: 30px;
-                overflow: hidden;
-
-                .swiper-item {
-                    width: 230px;
-                    height: 90px;
-                    background: #fff;
-                    border-radius: 12px;
-                    display: flex;
-                    justify-content: center;
-                    align-items: center;
-                    cursor: pointer;
-
-                    &:hover {
-                        background: #00aea3;
-
-                        >div>p {
-                            color: #fff;
-                        }
-                    }
-
-                    >div {
-                        display: flex;
-                        align-items: center;
-
-                        >p {
-                            font-weight: 600;
-                            color: #000;
-                            margin-left: 12px;
-                            font-size: 18px;
-                        }
-                    }
-                }
+            > p {
+              font-weight: 600;
+              color: #000;
+              margin-left: 12px;
+              font-size: 18px;
             }
+          }
         }
+      }
     }
+  }
 }
 
 .bg {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background-color: #f8f9fc;
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
-    z-index: 1;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: #f8f9fc;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  z-index: 1;
 }
 </style>

+ 150 - 155
src/views/Knowledge.vue

@@ -1,173 +1,168 @@
 <template>
-    <div id="app">
-        <Slider>
-            <Directory />
-        </Slider>
-        <div class="main">
-            <header>
-                <top-bar @choose-nav="chooseNav" />
-            </header>
-            <section>
-                <dialog-wrap
-                    :suggestions="suggestions"
-                    :isSetting="false"
-                    :readonly="readonly"
-                    @setReadonly="setReadonly"
-                />
-            </section>
-            <footer>
-                <message-input :readonly="readonly" />
-            </footer>
-        </div>
-        <record-list :data="recordList" :open="isOpenRecord" @closeRecord="closeRecord" @handleSelect="handleSelect" />
+  <div id="app">
+    <Slider>
+      <Directory />
+    </Slider>
+    <div class="main">
+      <header>
+        <top-bar @choose-nav="chooseNav" />
+      </header>
+      <section>
+        <dialog-wrap :suggestions="suggestions" :isSetting="false" :readonly="readonly" @setReadonly="setReadonly" />
+      </section>
+      <footer>
+        <message-input :readonly="readonly" />
+      </footer>
     </div>
+    <record-list :data="recordList" :open="isOpenRecord" @closeRecord="closeRecord" @handleSelect="handleSelect" />
+  </div>
 </template>
 <script>
-import Slider from "../components/Slider.vue";
-import DialogWrap from "../components/DialogWrap.vue";
-import MessageInput from "../components/MessageInput.vue";
-import TopBar from "../components/TopBar.vue";
-import Directory from "../components/Directory.vue";
-import RecordList from "../components/RecordList.vue";
-import { defineComponent, ref, inject } from "vue";
+import Slider from '../components/Slider.vue';
+import DialogWrap from '../components/DialogWrap.vue';
+import MessageInput from '../components/MessageInput.vue';
+import TopBar from '../components/TopBar.vue';
+import Directory from '../components/Directory.vue';
+import RecordList from '../components/RecordList.vue';
+import { defineComponent, ref, inject } from 'vue';
 export default defineComponent({
-    components: {
-        Slider,
-        DialogWrap,
-        MessageInput,
-        TopBar,
-        Directory,
-        RecordList
-    },
-    setup() {
-        const { helper } = inject("$global");
-        const suggestions = ["有没有关于AI agent的论文"];
-        const readonly = ref(false);
-        const isOpenRecord = ref(false);
-        const recordList = ref([
-            {
-                name: "今天",
-                list: [
-                    "你必须知道的8种产品设计能力提升技巧",
-                    "干货|学会写简历,轻松拿offer",
-                    "探索了5种改善移动用户体验的绝佳做",
-                    "通知必读,再不看就晚啦",
-                    "最佳产品管理书籍在此,获取职场上升上"
-                ]
+  components: {
+    Slider,
+    DialogWrap,
+    MessageInput,
+    TopBar,
+    Directory,
+    RecordList
+  },
+  setup() {
+    const { helper } = inject('$global');
+    const suggestions = ['有没有关于AI agent的论文'];
+    const readonly = ref(false);
+    const isOpenRecord = ref(false);
+    const recordList = ref([
+      {
+        name: '今天',
+        list: [
+          '你必须知道的8种产品设计能力提升技巧',
+          '干货|学会写简历,轻松拿offer',
+          '探索了5种改善移动用户体验的绝佳做',
+          '通知必读,再不看就晚啦',
+          '最佳产品管理书籍在此,获取职场上升上'
+        ]
+      },
+      {
+        name: '昨天',
+        list: ['探索了5种改善移动用户体验的绝佳做', '面试攻略:超级加分的10个面试满分小技']
+      },
+      {
+        name: '过去7天',
+        list: [
+          '你必须知道的8种产品设计能力提升技巧',
+          '干货|学会写简历,轻松拿offer',
+          '探索了5种改善移动用户体验的绝佳做',
+          '通知必读,再不看就晚啦',
+          '最佳产品管理书籍在此,获取职场上升上'
+        ]
+      },
+      {
+        name: '过去半年',
+        list: ['探索了5种改善移动用户体验的绝佳做', '面试攻略:超级加分的10个面试满分小技']
+      },
+      {
+        name: '更久以前',
+        list: [
+          '你必须知道的8种产品设计能力提升技巧',
+          '干货|学会写简历,轻松拿offer',
+          '探索了5种改善移动用户体验的绝佳做',
+          '通知必读,再不看就晚啦',
+          '最佳产品管理书籍在此,获取职场上升上'
+        ]
+      }
+    ]);
+    const handleSelect = (value, index, key, e) => {
+      switch (value) {
+        case 'delete':
+          recordList.value[index].list.splice(key, 1);
+          break;
+        case 'edit':
+          const div = document.getElementById(`recod-item-${index}-${key}`);
+          const wrapDiv = div.cloneNode();
+          const { width, height, top, left } = div.getBoundingClientRect();
+          wrapDiv.style.width = `${width}px`;
+          wrapDiv.style.height = `${height}px`;
+          wrapDiv.style.top = `${top}px`;
+          wrapDiv.style.left = `${left}px`;
+          wrapDiv.style.position = 'absolute';
+          const inputNode = document.createElement('input');
+          inputNode.value = recordList.value[index].list[key];
+          inputNode.style = 'width: 100%;height: 100%';
+          wrapDiv.append(inputNode);
+          helper.setDialog(
+            true,
+            wrapDiv,
+            () => {
+              inputNode.focus();
             },
-            {
-                name: "昨天",
-                list: ["探索了5种改善移动用户体验的绝佳做", "面试攻略:超级加分的10个面试满分小技"]
-            },
-            {
-                name: "过去7天",
-                list: [
-                    "你必须知道的8种产品设计能力提升技巧",
-                    "干货|学会写简历,轻松拿offer",
-                    "探索了5种改善移动用户体验的绝佳做",
-                    "通知必读,再不看就晚啦",
-                    "最佳产品管理书籍在此,获取职场上升上"
-                ]
-            },
-            {
-                name: "过去半年",
-                list: ["探索了5种改善移动用户体验的绝佳做", "面试攻略:超级加分的10个面试满分小技"]
-            },
-            {
-                name: "更久以前",
-                list: [
-                    "你必须知道的8种产品设计能力提升技巧",
-                    "干货|学会写简历,轻松拿offer",
-                    "探索了5种改善移动用户体验的绝佳做",
-                    "通知必读,再不看就晚啦",
-                    "最佳产品管理书籍在此,获取职场上升上"
-                ]
-            }
-        ]);
-        const handleSelect = (value, index, key, e) => {
-            switch (value) {
-                case "delete":
-                    recordList.value[index].list.splice(key, 1);
-                    break;
-                case "edit":
-                    const div = document.getElementById(`recod-item-${index}-${key}`);
-                    const wrapDiv = div.cloneNode();
-                    const { width, height, top, left } = div.getBoundingClientRect();
-                    wrapDiv.style.width = `${width}px`;
-                    wrapDiv.style.height = `${height}px`;
-                    wrapDiv.style.top = `${top}px`;
-                    wrapDiv.style.left = `${left}px`;
-                    wrapDiv.style.position = "absolute";
-                    const inputNode = document.createElement("input");
-                    inputNode.value = recordList.value[index].list[key];
-                    inputNode.style = "width: 100%;height: 100%";
-                    wrapDiv.append(inputNode);
-                    helper.setDialog(
-                        true,
-                        wrapDiv,
-                        () => {
-                            inputNode.focus();
-                        },
-                        () => {
-                            recordList.value[index].list[key] = inputNode.value;
-                        }
-                    );
-                    break;
+            () => {
+              recordList.value[index].list[key] = inputNode.value;
             }
-        };
-        const openRecord = () => (isOpenRecord.value = true);
-        const chooseNav = (index) => {
-            switch (index) {
-                case 2:
-                    openRecord();
-                    break;
-            }
-        };
-        const closeRecord = () => (isOpenRecord.value = false);
-        const setReadonly = (status) => {
-            readonly.value = status;
-        };
-        return {
-            recordList,
-            isOpenRecord,
-            readonly,
-            setReadonly,
-            suggestions,
-            handleSelect,
-            openRecord,
-            closeRecord,
-            chooseNav
-        };
-    }
+          );
+          break;
+      }
+    };
+    const openRecord = () => (isOpenRecord.value = true);
+    const chooseNav = (index) => {
+      switch (index) {
+        case 2:
+          openRecord();
+          break;
+      }
+    };
+    const closeRecord = () => (isOpenRecord.value = false);
+    const setReadonly = (status) => {
+      readonly.value = status;
+    };
+    return {
+      recordList,
+      isOpenRecord,
+      readonly,
+      setReadonly,
+      suggestions,
+      handleSelect,
+      openRecord,
+      closeRecord,
+      chooseNav
+    };
+  }
 });
 </script>
 <style>
 .arco-message-list-top {
-    top: 350px !important;
+  top: 350px !important;
 }
 </style>
 <style scoped>
 .main {
-    flex: 1;
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  background: #fbfbfb;
+  overflow-y: auto;
+  > header {
     display: flex;
-    flex-direction: column;
-    background: #fbfbfb;
-    overflow-y: auto;
-    > header {
-        display: flex;
-        align-items: center;
-        justify-content: right;
-        padding: 0 20px;
-        height: 50px;
-        border-bottom: 1px solid rgba(229, 229, 229, 1);
-    }
-    > section {
-        padding: 0 80px;
-        flex: 1;
-    }
-    > footer {
-        padding: 0 80px;
-        margin-top: 80px;
-    }
+    align-items: center;
+    justify-content: right;
+    padding: 0 20px;
+    height: 50px;
+    border-bottom: 1px solid rgba(229, 229, 229, 1);
+  }
+  > section {
+    padding: 0 80px;
+    flex: 1;
+  }
+  > footer {
+    padding: 0 80px;
+    margin-top: 80px;
+  }
 }
 </style>

+ 137 - 139
src/views/Login.vue

@@ -1,164 +1,162 @@
 <template>
-    <main>
-        <section>
-            <header>
-                <img src="@/assets/login.png" />
-                <p>欢迎使用</p>
-            </header>
-            <p>账号登录</p>
-            <section>
-                <p>账号</p>
-                <div>
-                    <a-input placeholder="请输入手机号" :style="{ width: '250px', height: '40px' }" v-model="username">
-                    </a-input>
-                </div>
-            </section>
-            <section>
-                <p>密码</p>
-                <div>
-                    <a-input-password placeholder="请输入手机号" :style="{ width: '250px', height: '40px' }"
-                        v-model="password">
-                    </a-input-password>
-                </div>
-            </section>
-            <section>
-                <p style="cursor: pointer" @click="goRegister">去注册</p>
-            </section>
-            <div @click="login">登录</div>
-        </section>
-    </main>
+  <main>
+    <section>
+      <header>
+        <img src="@/assets/login.png" />
+        <p>欢迎使用</p>
+      </header>
+      <p>账号登录</p>
+      <section>
+        <p>账号</p>
+        <div>
+          <a-input placeholder="请输入手机号" :style="{ width: '250px', height: '40px' }" v-model="username"> </a-input>
+        </div>
+      </section>
+      <section>
+        <p>密码</p>
+        <div>
+          <a-input-password placeholder="请输入手机号" :style="{ width: '250px', height: '40px' }" v-model="password">
+          </a-input-password>
+        </div>
+      </section>
+      <section>
+        <p style="cursor: pointer" @click="goRegister">去注册</p>
+      </section>
+      <div @click="login">登录</div>
+    </section>
+  </main>
 </template>
 <script>
-import { defineComponent, ref, inject } from "vue";
+import { defineComponent, ref, inject } from 'vue';
 export default defineComponent({
-    components: {},
-    props: [],
-    setup() {
-        const { ajax, helper } = inject("$global");
-        const username = ref("");
-        const password = ref("");
-        const login = async () => {
-            const result = await ajax.user.login(username.value, password.value);
-            if (result) {
-                // TODO 登录成功后,处理菜单之后储存
+  components: {},
+  props: [],
+  setup() {
+    const { ajax, helper } = inject('$global');
+    const username = ref('');
+    const password = ref('');
+    const login = async () => {
+      const result = await ajax.user.login(username.value, password.value);
+      if (result) {
+        // TODO 登录成功后,处理菜单之后储存
 
-                helper.write("userName", result.nickname || result.username);
-                helper.write("token", result.access_token);
-                helper.goLink("/");
-            }
-        };
-        const goRegister = () => {
-            helper.goLink("register");
-        };
-        return {
-            login,
-            username,
-            password,
-            goRegister
-        };
-    }
+        helper.write('userName', result.nickname || result.username);
+        helper.write('token', result.access_token);
+        helper.goLink('/');
+      }
+    };
+    const goRegister = () => {
+      helper.goLink('register');
+    };
+    return {
+      login,
+      username,
+      password,
+      goRegister
+    };
+  }
 });
 </script>
 <style scoped>
 main {
-    width: 100vw;
-    height: 100vh;
-    align-items: center;
-    justify-content: center;
-    display: flex;
-    position: relative;
+  width: 100vw;
+  height: 100vh;
+  align-items: center;
+  justify-content: center;
+  display: flex;
+  position: relative;
 
-    >p {
-        position: absolute;
-        bottom: 30px;
-        color: rgba(153, 153, 153, 1);
-        font-size: 14px;
-    }
+  > p {
+    position: absolute;
+    bottom: 30px;
+    color: rgba(153, 153, 153, 1);
+    font-size: 14px;
+  }
 
-    >section {
-        width: 640px;
-        border-radius: 12px;
-        background-color: rgba(255, 255, 255, 0.52);
-        box-shadow: 0px 2px 20px -2px rgba(0, 0, 0, 0.1);
-        border: 1px solid rgba(187, 187, 187, 1);
+  > section {
+    width: 640px;
+    border-radius: 12px;
+    background-color: rgba(255, 255, 255, 0.52);
+    box-shadow: 0px 2px 20px -2px rgba(0, 0, 0, 0.1);
+    border: 1px solid rgba(187, 187, 187, 1);
 
-        >header {
-            height: 130px;
-            background-color: rgba(65, 95, 235, 0.05);
-            position: relative;
+    > header {
+      height: 130px;
+      background-color: rgba(65, 95, 235, 0.05);
+      position: relative;
 
-            img {
-                height: 130px;
-                position: absolute;
-                top: 0;
-                right: 0;
-            }
+      img {
+        height: 130px;
+        position: absolute;
+        top: 0;
+        right: 0;
+      }
 
-            p {
-                height: 130px;
-                line-height: 130px;
-                position: absolute;
-                left: 30px;
-                z-index: 2;
-                color: rgba(51, 51, 51, 1);
-                font-size: 36px;
-                font-weight: bold;
-            }
-        }
+      p {
+        height: 130px;
+        line-height: 130px;
+        position: absolute;
+        left: 30px;
+        z-index: 2;
+        color: rgba(51, 51, 51, 1);
+        font-size: 36px;
+        font-weight: bold;
+      }
+    }
 
-        >p {
-            text-align: center;
+    > p {
+      text-align: center;
 
-            &:nth-child(2) {
-                margin: 60px 0 10px 0;
-                color: rgba(16, 16, 16, 1);
-                font-size: 28px;
-                font-weight: bold;
-            }
+      &:nth-child(2) {
+        margin: 60px 0 10px 0;
+        color: rgba(16, 16, 16, 1);
+        font-size: 28px;
+        font-weight: bold;
+      }
 
-            &:nth-child(3) {
-                color: rgba(102, 102, 102, 1);
-                font-size: 18px;
-            }
-        }
+      &:nth-child(3) {
+        color: rgba(102, 102, 102, 1);
+        font-size: 18px;
+      }
+    }
 
-        >section {
-            display: flex;
-            justify-content: center;
-            margin-top: 20px;
+    > section {
+      display: flex;
+      justify-content: center;
+      margin-top: 20px;
 
-            >p {
-                display: flex;
-                align-items: center;
-                margin-right: 10px;
-            }
-        }
+      > p {
+        display: flex;
+        align-items: center;
+        margin-right: 10px;
+      }
+    }
 
-        >div {
-            width: 332px;
-            height: 40px;
-            border-radius: 4px;
-            background-color: rgba(64, 95, 234, 1);
-            color: rgba(255, 255, 255, 1);
-            font-size: 14px;
-            text-align: center;
-            box-shadow: 0px 2px 6px -2px rgba(64, 95, 234, 0.53);
-            line-height: 40px;
-            border: 1px solid rgba(64, 95, 234, 1);
-            margin: 30px auto;
-            cursor: pointer;
+    > div {
+      width: 332px;
+      height: 40px;
+      border-radius: 4px;
+      background-color: rgba(64, 95, 234, 1);
+      color: rgba(255, 255, 255, 1);
+      font-size: 14px;
+      text-align: center;
+      box-shadow: 0px 2px 6px -2px rgba(64, 95, 234, 0.53);
+      line-height: 40px;
+      border: 1px solid rgba(64, 95, 234, 1);
+      margin: 30px auto;
+      cursor: pointer;
 
-            &:hover {
-                background-color: rgba(64, 95, 234, 0.8);
-            }
-        }
+      &:hover {
+        background-color: rgba(64, 95, 234, 0.8);
+      }
+    }
 
-        >span {
-            display: block;
-            widows: 100%;
-            text-align: center;
-            margin-bottom: 30px;
-        }
+    > span {
+      display: block;
+      widows: 100%;
+      text-align: center;
+      margin-bottom: 30px;
     }
+  }
 }
 </style>

+ 33 - 36
src/views/PicArticle.vue

@@ -1,5 +1,5 @@
 <template>
-<main>
+  <main>
     <section class="xiaoshuhuitu-sections">
       <div v-for="(item, key) in data" :key="key" :style="{ background: item.background }">
         <img :src="getAssetURL(item.img)" />
@@ -9,51 +9,48 @@
         </div>
       </div>
     </section>
-</main>
+  </main>
 </template>
 <script>
-import { defineComponent, ref, inject, reactive } from "vue";
+import { defineComponent, ref, inject, reactive } from 'vue';
 export default defineComponent({
-    components: {
-        
-    },
-    setup() {
-        const { helper, ajax } = inject("$global");
+  components: {},
+  setup() {
+    const { helper, ajax } = inject('$global');
 
-        const data = ref([
-            {
-                background: "rgba(72, 177, 244, 0.06)",
-                color: "rgb(72, 177, 244)",
-                img: "/src/assets/gen/5.png",
-                title: "上传图片",
-                content: "支持支持PNG,JPG等格式图片,大小在10M以内"
-            },
-            {
-                background: "rgba(158, 128, 255, 0.06)",
-                color: "rgb(158, 128, 255)",
-                img: "/src/assets/gen/6.png",
-                title: "多轮问答",
-                content: "基于图片内容,实现的多轮问答"
-            }
-        ]);
-        return {
-            data,
+    const data = ref([
+      {
+        background: 'rgba(72, 177, 244, 0.06)',
+        color: 'rgb(72, 177, 244)',
+        img: '/src/assets/gen/5.png',
+        title: '上传图片',
+        content: '支持支持PNG,JPG等格式图片,大小在10M以内'
+      },
+      {
+        background: 'rgba(158, 128, 255, 0.06)',
+        color: 'rgb(158, 128, 255)',
+        img: '/src/assets/gen/6.png',
+        title: '多轮问答',
+        content: '基于图片内容,实现的多轮问答'
+      }
+    ]);
+    return {
+      data,
 
-            getAssetURL: helper.getAssetURL,
-        };
-    }
+      getAssetURL: helper.getAssetURL
+    };
+  }
 });
 </script>
 
 <style lang="scss" scoped>
-
 main {
   height: 100%;
   display: flex;
   flex-direction: column;
   overflow: hidden;
 
-  >section {
+  > section {
     overflow-y: auto;
     display: flex;
     flex-wrap: wrap;
@@ -63,24 +60,24 @@ main {
       flex: 1;
     }
 
-    >div {
+    > div {
       width: 382px;
       height: 120px;
       padding: 20px 24px;
       border-radius: 8px;
       display: flex;
 
-      >img {
+      > img {
         width: 38px;
         height: 38px;
         margin-right: 12px;
       }
 
-      >div {
+      > div {
         font-size: 18px;
         font-weight: bold;
 
-        >span {
+        > span {
           font-size: 15px;
           font-weight: 400;
           color: #797d7f;
@@ -96,4 +93,4 @@ main {
     }
   }
 }
-</style>
+</style>

+ 130 - 131
src/views/Register.vue

@@ -1,145 +1,144 @@
 <template>
-    <main>
-        <section>
-            <header>
-                <img src="@/assets/login.png" />
-                <p>欢迎使用</p>
-            </header>
-            <p>账号注册</p>
-            <section>
-                <p>账号</p>
-                <div>
-                    <a-input placeholder="请输入账号" :style="{ width: '250px', height: '40px' }" v-model="username">
-                    </a-input>
-                </div>
-            </section>
-            <section>
-                <p>密码</p>
-                <div>
-                    <a-input-password
-                        type="password"
-                        placeholder="请输入密码"
-                        :style="{ width: '250px', height: '40px' }"
-                        v-model="password"
-                    >
-                    </a-input-password>
-                </div>
-            </section>
-            <div @click="register">注册</div>
-        </section>
-    </main>
+  <main>
+    <section>
+      <header>
+        <img src="@/assets/login.png" />
+        <p>欢迎使用</p>
+      </header>
+      <p>账号注册</p>
+      <section>
+        <p>账号</p>
+        <div>
+          <a-input placeholder="请输入账号" :style="{ width: '250px', height: '40px' }" v-model="username"> </a-input>
+        </div>
+      </section>
+      <section>
+        <p>密码</p>
+        <div>
+          <a-input-password
+            type="password"
+            placeholder="请输入密码"
+            :style="{ width: '250px', height: '40px' }"
+            v-model="password"
+          >
+          </a-input-password>
+        </div>
+      </section>
+      <div @click="register">注册</div>
+    </section>
+  </main>
 </template>
 <script>
-import { defineComponent, ref, inject } from "vue";
+import { defineComponent, ref, inject } from 'vue';
 export default defineComponent({
-    components: {},
-    props: [],
-    setup() {
-        const { ajax, helper } = inject("$global");
-        const username = ref("");
-        const password = ref("");
-        const register = async () => {
-            const result = await ajax.user.register(username.value, password.value);
-            if (result) {
-                helper.write("userName", String(result.username));
-                helper.goLink("/login");
-            }
-        };
-        return {
-            register,
-            username,
-            password
-        };
-    }
+  components: {},
+  props: [],
+  setup() {
+    const { ajax, helper } = inject('$global');
+    const username = ref('');
+    const password = ref('');
+    const register = async () => {
+      const result = await ajax.user.register(username.value, password.value);
+      if (result) {
+        helper.write('userName', String(result.username));
+        helper.goLink('/login');
+      }
+    };
+    return {
+      register,
+      username,
+      password
+    };
+  }
 });
 </script>
 <style scoped>
 main {
-    width: 100vw;
-    height: 100vh;
-    align-items: center;
-    justify-content: center;
-    display: flex;
-    position: relative;
-    > p {
+  width: 100vw;
+  height: 100vh;
+  align-items: center;
+  justify-content: center;
+  display: flex;
+  position: relative;
+  > p {
+    position: absolute;
+    bottom: 30px;
+    color: rgba(153, 153, 153, 1);
+    font-size: 14px;
+  }
+  > section {
+    width: 640px;
+    border-radius: 12px;
+    background-color: rgba(255, 255, 255, 0.52);
+    box-shadow: 0px 2px 20px -2px rgba(0, 0, 0, 0.1);
+    border: 1px solid rgba(187, 187, 187, 1);
+    > header {
+      height: 130px;
+      background-color: rgba(65, 95, 235, 0.05);
+      position: relative;
+      img {
+        height: 130px;
         position: absolute;
-        bottom: 30px;
-        color: rgba(153, 153, 153, 1);
-        font-size: 14px;
+        top: 0;
+        right: 0;
+      }
+      p {
+        height: 130px;
+        line-height: 130px;
+        position: absolute;
+        left: 30px;
+        z-index: 2;
+        color: rgba(51, 51, 51, 1);
+        font-size: 36px;
+        font-weight: bold;
+      }
+    }
+    > p {
+      text-align: center;
+      &:nth-child(2) {
+        margin: 60px 0 10px 0;
+        color: rgba(16, 16, 16, 1);
+        font-size: 28px;
+        font-weight: bold;
+      }
+      &:nth-child(3) {
+        color: rgba(102, 102, 102, 1);
+        font-size: 18px;
+      }
     }
     > section {
-        width: 640px;
-        border-radius: 12px;
-        background-color: rgba(255, 255, 255, 0.52);
-        box-shadow: 0px 2px 20px -2px rgba(0, 0, 0, 0.1);
-        border: 1px solid rgba(187, 187, 187, 1);
-        > header {
-            height: 130px;
-            background-color: rgba(65, 95, 235, 0.05);
-            position: relative;
-            img {
-                height: 130px;
-                position: absolute;
-                top: 0;
-                right: 0;
-            }
-            p {
-                height: 130px;
-                line-height: 130px;
-                position: absolute;
-                left: 30px;
-                z-index: 2;
-                color: rgba(51, 51, 51, 1);
-                font-size: 36px;
-                font-weight: bold;
-            }
-        }
-        > p {
-            text-align: center;
-            &:nth-child(2) {
-                margin: 60px 0 10px 0;
-                color: rgba(16, 16, 16, 1);
-                font-size: 28px;
-                font-weight: bold;
-            }
-            &:nth-child(3) {
-                color: rgba(102, 102, 102, 1);
-                font-size: 18px;
-            }
-        }
-        > section {
-            display: flex;
-            justify-content: center;
-            margin-top: 20px;
-            > p {
-                display: flex;
-                align-items: center;
-                margin-right: 10px;
-            }
-        }
-        > div {
-            width: 332px;
-            height: 40px;
-            border-radius: 4px;
-            background-color: rgba(64, 95, 234, 1);
-            color: rgba(255, 255, 255, 1);
-            font-size: 14px;
-            text-align: center;
-            box-shadow: 0px 2px 6px -2px rgba(64, 95, 234, 0.53);
-            line-height: 40px;
-            border: 1px solid rgba(64, 95, 234, 1);
-            margin: 30px auto;
-            cursor: pointer;
-            &:hover {
-                background-color: rgba(64, 95, 234, 0.8);
-            }
-        }
-        > span {
-            display: block;
-            widows: 100%;
-            text-align: center;
-            margin-bottom: 30px;
-        }
+      display: flex;
+      justify-content: center;
+      margin-top: 20px;
+      > p {
+        display: flex;
+        align-items: center;
+        margin-right: 10px;
+      }
+    }
+    > div {
+      width: 332px;
+      height: 40px;
+      border-radius: 4px;
+      background-color: rgba(64, 95, 234, 1);
+      color: rgba(255, 255, 255, 1);
+      font-size: 14px;
+      text-align: center;
+      box-shadow: 0px 2px 6px -2px rgba(64, 95, 234, 0.53);
+      line-height: 40px;
+      border: 1px solid rgba(64, 95, 234, 1);
+      margin: 30px auto;
+      cursor: pointer;
+      &:hover {
+        background-color: rgba(64, 95, 234, 0.8);
+      }
+    }
+    > span {
+      display: block;
+      widows: 100%;
+      text-align: center;
+      margin-bottom: 30px;
     }
+  }
 }
 </style>

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません