Przeglądaj źródła

fix:解决ai转写 无法问答问题

hanyang 1 rok temu
rodzic
commit
2c8889cd4e

+ 20 - 0
public/i18n/lang-en.json

@@ -146,6 +146,26 @@
       "label_attend": "Attendance Penalty",
       "label_frequency": "Frequency Penalty",
       "max_token_count": "Max Token Count"
+    },
+    "share": "Share",
+    "share_way_tip": "Select the sharing method",
+    "team_member": "Team Member",
+    "copy_link": "Copy Link",
+    "qr_code": "QR Code",
+    "table": {
+      "name": "Username",
+      "add_time": "Join Time",
+      "status": "Status",
+      "permission": "Permission",
+      "operate": "Operation",
+      "transfer": "Transfer",
+      "transfer_tips": "This operation cannot be revoked. Please carefully confirm whether to transfer this knowledge base?",
+      "forbidden": "Disable",
+      "forbidden_tips": "Please confirm whether to disable this member's access to this knowledge base?",
+      "delete": "Delete",
+      "delete_tips": "Please confirm whether to delete this member?",
+      "member_select": "Member Selection",
+      "member_select_tip": "Please select a member"
     }
   },
   "knowledgeLib": {

+ 20 - 0
public/i18n/lang-zh.json

@@ -146,6 +146,26 @@
       "label_attend": "出席处罚",
       "label_frequency": "频率处罚",
       "max_token_count": "最大token数"
+    },
+    "share": "分享",
+    "share_way_tip": "选择分享方式",
+    "team_member": "团队成员",
+    "copy_link": "复制链接",
+    "qr_code": "二维码",
+    "table": {
+      "name": "用户名",
+      "add_time": "加入时间",
+      "status": "状态",
+      "permission": "权限",
+      "operate": "操作",
+      "transfer": "转让",
+      "transfer_tips": "操作不可撤销,请仔细确认是否转让该知识库?",
+      "forbidden": "禁用",
+      "forbidden_tips": "请确认是否禁用该成员访问此知识库?",
+      "delete": "删除",
+      "delete_tips": "请确认是否删除该成员?",
+      "member_select": "成员选择",
+      "member_select_tip": "请选择成员"
     }
   },
   "knowledgeLib": {

BIN
src/assets/image/management/qr-code.png


BIN
src/assets/image/management/share-link.png


BIN
src/assets/image/management/share.png


+ 1 - 0
src/base/theme/theme-dark.css

@@ -3,4 +3,5 @@ html body[dmx-theme='dark'] {
   --color-text-2: #707379;
   --color-bolder-11: #007aff;
   --color-icon-1: #668ff3;
+  --color-text-title: #7c7c7c;
 }

+ 1 - 0
src/base/theme/theme-light.css

@@ -2,6 +2,7 @@ html body[dmx-theme='light'] {
   --color-text-1: #1f2022;
   --color-text-2: #707379;
   --color-text-3: #a4a8b1;
+  --color-text-title: #7c7c7c;
 
   --color-bg-1: #fff;
   /* --color-bg-2: #fff;

+ 2 - 0
src/base/theme/theme-party.css

@@ -9,6 +9,8 @@ html body[dmx-theme='party'] {
   --bg-img: url('../../assets/party-bg.jpeg');
   --color-bolder-11: #007aff;
   --color-icon-1: #668ff3;
+  --color-link-1: #165dff;
+  --color-text-title: #7c7c7c;
 }
 
 /*

Plik diff jest za duży
+ 1 - 13
src/components/11.json


+ 2 - 1
src/modules/conversation-ai-editor/AIEditor.vue

@@ -90,7 +90,7 @@ onMounted(() => {
           },
           parseMessage: (message) => {
             let result = '';
-            // console.log(JSON.parse(message));
+            console.log(JSON.parse(message));
             if (JSON.parse(message).event === 'stream') {
               result += JSON.parse(message).data.answer;
             }
@@ -130,6 +130,7 @@ onMounted(() => {
     }
   });
   aiEditor.setMarkdownContent(props.content);
+  // 获取divRef中所有的P标签
 });
 
 onUnmounted(() => {

+ 291 - 0
src/modules/conversation-ai-editor/AIEditor_v2.vue

@@ -0,0 +1,291 @@
+<template>
+  <div ref="divRef" :style="editor_style" class="editor"></div>
+</template>
+
+<script setup>
+import LinwitDocEditor from '../../3rd-libs/linwitdoc-editor.js';
+import 'linwitdoc-editor/dist/style.css';
+import { nextTick, watch, onMounted, onUnmounted, ref } from 'vue';
+import { kuky_Authorization } from '../../base/storage';
+import { getConfigField } from '../../config/index';
+
+import { getContentStr, getContentType } from './use-regex';
+const props = defineProps({
+  content: {
+    type: String,
+    default: '欢迎'
+  },
+  editor_style: {
+    type: Object,
+    default: () => {
+      return {
+        width: '100%',
+        height: '100%',
+        // overflow: 'hidden'
+        padding: '10px 20px',
+        boxSizing: 'border-box'
+      };
+    }
+  }
+});
+let base_url = '';
+if (import.meta.env.MODE === 'production') {
+  base_url = getConfigField('API_BASE_URL');
+} else {
+  base_url = '';
+}
+
+const divRef = ref();
+let aiEditor = null;
+
+const token = kuky_Authorization.get();
+
+// 监听鼠标进入 p 标签
+const handleMouseOver = (event) => {
+  console.log(event);
+  const target = event.target;
+  console.log(target);
+
+  // 仅对 p 标签进行操作
+  if (target.tagName.toLowerCase() === 'p') {
+    showAIBtn(target);
+  }
+};
+// 显示 AI 转写按钮
+const showAIBtn = (pElement) => {
+  const existingBtn = pElement.querySelector('.ai-btn');
+  if (!existingBtn) {
+    const btn = document.createElement('button');
+    btn.innerText = 'AI 111转写';
+    btn.classList.add('ai-btn');
+    btn.style.position = 'absolute';
+    btn.style.left = '0';
+    btn.style.top = '-100px';
+    btn.style.padding = '5px 10px';
+    btn.style.fontSize = '14px';
+    btn.style.backgroundColor = '#007bff';
+    btn.style.color = '#fff';
+    btn.style.border = 'none';
+    btn.style.cursor = 'pointer';
+    btn.style.borderRadius = '4px';
+    btn.addEventListener('click', () => {
+      alert('AI 转写功能');
+    });
+
+    pElement.style.position = 'relative';
+    pElement.appendChild(btn);
+  }
+};
+
+const handleMouseEnter = (pElement) => {
+  // 如果已经存在按钮,则不再添加
+  const existingBtn = pElement.querySelector('.ai-btn');
+  if (!existingBtn) {
+    const btn = document.createElement('button');
+    btn.innerText = 'AI 111转写';
+    btn.classList.add('ai-btn');
+    btn.style.position = 'absolute';
+    btn.style.top = '0';
+    btn.style.left = '-90px'; // 在 p 标签的前面显示
+    btn.style.padding = '5px 10px';
+    btn.style.fontSize = '14px';
+    btn.style.backgroundColor = '#007bff';
+    btn.style.color = '#fff';
+    btn.style.border = 'none';
+    btn.style.cursor = 'pointer';
+    btn.style.borderRadius = '4px';
+    btn.addEventListener('click', () => {
+      alert('AI 转写功能');
+    });
+
+    // 设置 p 元素为相对定位,确保按钮能相对于 p 元素定位
+    pElement.style.position = 'relative';
+    pElement.appendChild(btn);
+
+    // 给按钮本身添加 mouseleave 事件
+    btn.addEventListener('mouseleave', () => handleMouseLeave(pElement));
+  }
+};
+
+const handleMouseLeave = (pElement) => {
+  // 鼠标离开时移除按钮
+  const existingBtn = pElement.querySelector('.ai-btn');
+  if (existingBtn) {
+    pElement.removeChild(existingBtn);
+  }
+};
+// 确保鼠标离开 p 标签时触发 handleMouseLeave
+const handleParentMouseLeave = (event) => {
+  const pElement = event.target;
+  handleMouseLeave(pElement);
+};
+const getAllPTags = (parentNode) => {
+  const pTags = [];
+
+  const traverse = (node) => {
+    if (node.tagName === 'P') {
+      pTags.push(node);
+    }
+    // 递归遍历子节点
+    for (let i = 0; i < node.children.length; i++) {
+      traverse(node.children[i]);
+    }
+  };
+
+  traverse(parentNode);
+  return pTags;
+};
+
+watch(
+  () => props.content,
+  () => {
+    aiEditor.setMarkdownContent(props.content);
+  }
+);
+// 获取文本
+const getMarkDownContent = () => {
+  console.log(aiEditor.getHtml());
+  return aiEditor.getMarkdown();
+};
+const getHTMLContent = () => {
+  return aiEditor.getHtml();
+};
+onMounted(() => {
+  aiEditor = new LinwitDocEditor({
+    element: divRef.value,
+    toolbarKeys: [],
+    placeholder: '点击输入内容...',
+    textSelectionBubbleMenu: {
+      enable: true,
+      items: ['ai', 'Bold', 'Italic', 'Underline', 'Strike', 'code']
+    },
+
+    ai: {
+      models: {
+        custom: {
+          url: base_url + '/api/v1/complex/chat/completions',
+          headers: () => {
+            return {
+              Authorization: 'Bearer ' + token,
+              'Content-Type': 'application/json',
+              Accept: 'text/event-stream',
+              Connection: 'keep-alive'
+            };
+          },
+          wrapPayload: (message) => {
+            const query = getContentStr(message);
+            const optimizeType = getContentType(message);
+            return JSON.stringify({
+              query: query,
+              isDeep: 1,
+              chatMode: 4,
+              sessionId: '',
+              optimizeType: optimizeType,
+              files: null,
+              knowledgeId: []
+            });
+          },
+          parseMessage: (message) => {
+            let result = '';
+            // console.log(JSON.parse(message));
+            if (JSON.parse(message).event === 'stream') {
+              result += JSON.parse(message).data.answer;
+            }
+            return {
+              role: 'assistant',
+              content: result
+            };
+          },
+          protocol: 'sse'
+        }
+      },
+
+      bubblePanelEnable: true,
+      bubblePanelModel: 'auto',
+      bubblePanelMenus: [
+        {
+          prompt: `<content>{content}</content>请帮我润色一下这段内容,并直接返回润色后的结果.注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+          icon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M15.1986 9.94447C14.7649 9.5337 14.4859 8.98613 14.4085 8.39384L14.0056 5.31138L11.275 6.79724C10.7503 7.08274 10.1433 7.17888 9.55608 7.06948L6.49998 6.50015L7.06931 9.55625C7.17871 10.1435 7.08257 10.7505 6.79707 11.2751L5.31121 14.0057L8.39367 14.4086C8.98596 14.4861 9.53353 14.7651 9.94431 15.1987L12.0821 17.4557L13.4178 14.6486C13.6745 14.1092 14.109 13.6747 14.6484 13.418L17.4555 12.0823L15.1986 9.94447ZM15.2238 15.5079L13.0111 20.1581C12.8687 20.4573 12.5107 20.5844 12.2115 20.442C12.1448 20.4103 12.0845 20.3665 12.0337 20.3129L8.49229 16.5741C8.39749 16.474 8.27113 16.4096 8.13445 16.3918L3.02816 15.7243C2.69958 15.6814 2.46804 15.3802 2.51099 15.0516C2.52056 14.9784 2.54359 14.9075 2.5789 14.8426L5.04031 10.3192C5.1062 10.1981 5.12839 10.058 5.10314 9.92253L4.16 4.85991C4.09931 4.53414 4.3142 4.22086 4.63997 4.16017C4.7126 4.14664 4.78711 4.14664 4.85974 4.16017L9.92237 5.10331C10.0579 5.12855 10.198 5.10637 10.319 5.04048L14.8424 2.57907C15.1335 2.42068 15.4979 2.52825 15.6562 2.81931C15.6916 2.88421 15.7146 2.95507 15.7241 3.02833L16.3916 8.13462C16.4095 8.2713 16.4739 8.39766 16.5739 8.49245L20.3127 12.0338C20.5533 12.2617 20.5636 12.6415 20.3357 12.8821C20.2849 12.9357 20.2246 12.9795 20.1579 13.0112L15.5078 15.224C15.3833 15.2832 15.283 15.3835 15.2238 15.5079ZM16.0206 17.435L17.4348 16.0208L21.6775 20.2634L20.2633 21.6776L16.0206 17.435Z"></path></svg>`,
+          title: '润色'
+        },
+        {
+          prompt: `<content>{content}</content>请帮我扩写一下这段内容,并直接返回扩写后的结果。注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+          icon: ` <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24"><path fill="currentColor" d="M2 3c0-.552.497-1 1.111-1H20.89C21.503 2 22 2.448 22 3s-.497 1-1.111 1H3.11C2.497 4 2 3.552 2 3M2 9c0-.552.497-1 1.111-1H20.89C21.503 8 22 8.448 22 9s-.497 1-1.111 1H3.11C2.497 10 2 9.552 2 9M2 15c0-.552.497-1 1.111-1H20.89c.614 0 1.111.448 1.111 1s-.497 1-1.111 1H3.11C2.497 16 2 15.552 2 15M2 21c0-.552.497-1 1.111-1H13c.614 0 1.111.448 1.111 1s-.497 1-1.111 1H3.111C2.497 22 2 21.552 2 21"></path></svg>`,
+          title: '扩写'
+        },
+        {
+          prompt: `<content>{content}</content>请帮我缩写一下这段内容,并直接返回缩写后的结果。注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+          icon: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M2 9a1 1 0 0 1 1-1h18a1 1 0 1 1 0 2H3a1 1 0 0 1-1-1m1 5a1 1 0 1 0 0 2h12a1 1 0 1 0 0-2z" clip-rule="evenodd"></path></svg>`,
+          title: '缩写'
+        }
+        // {
+        //   // prompt: `<content>{content}</content>请帮我总结以上内容,并直接返回总结的结果\n注意:你应该先判断一下这句话是中文还是英文,如果是中文,请给我返回中文的内容,如果是英文,请给我返回英文内容,只需要返回内容即可,不需要告知我是中文还是英文。`,
+        //   icon: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24"><path fill="currentColor" d="M2.937 15.058a.89.89 0 0 1-.665-.282.94.94 0 0 1-.272-.675v-4.22q0-.392.272-.674a.87.87 0 0 1 .665-.292q.413 0 .684.292a.92.92 0 0 1 .282.675v4.22a.92.92 0 0 1-.282.674.91.91 0 0 1-.684.282m3.534 4.018a.92.92 0 0 1-.674-.271.95.95 0 0 1-.272-.685V5.864a.95.95 0 0 1 .272-.685.9.9 0 0 1 .674-.282.9.9 0 0 1 .675.282.93.93 0 0 1 .282.685V18.12a.93.93 0 0 1-.282.685.92.92 0 0 1-.675.271m3.515 3.807a.89.89 0 0 1-.665-.282.92.92 0 0 1-.271-.674V2.057q0-.404.271-.675a.89.89 0 0 1 .665-.282q.413 0 .685.282a.9.9 0 0 1 .282.675v19.87a.9.9 0 0 1-.282.674.91.91 0 0 1-.685.282m3.535-5.176a.92.92 0 0 1-.675-.272.92.92 0 0 1-.272-.675V7.223q0-.402.272-.675a.9.9 0 0 1 .675-.282.9.9 0 0 1 .675.282.9.9 0 0 1 .282.675v9.537a.9.9 0 0 1-.282.675.92.92 0 0 1-.675.272m3.535 2.96a.91.91 0 0 1-.685-.281.9.9 0 0 1-.272-.665V4.262q0-.393.272-.674a.91.91 0 0 1 .685-.282q.392 0 .665.282a.92.92 0 0 1 .282.674v15.459a.89.89 0 0 1-.282.665.89.89 0 0 1-.665.282m3.515-4.874a.9.9 0 0 1-.675-.282.94.94 0 0 1-.272-.674v-5.7q0-.393.272-.675a.9.9 0 0 1 .675-.282q.402 0 .684.282a.92.92 0 0 1 .282.675v5.7a.92.92 0 0 1-.282.674.93.93 0 0 1-.684.282"></path></svg>`,
+        //   title: '语气调整'
+        // }
+      ]
+    }
+  });
+  aiEditor.setMarkdownContent(props.content);
+
+  // 确保渲染完成后再操作 DOM
+  nextTick(() => {
+    // console.log(divRef.value.querySelectorAll('p'));
+    // const pTags = getAllPTags(divRef.value);
+    // console.log(pTags);
+    // pTags?.forEach((pTag) => {
+    //   pTag.addEventListener('mouseenter', () => handleMouseEnter(pTag));
+    //   pTag.addEventListener('mouseleave', handleParentMouseLeave);
+    // });
+    // const ele = document.querySelector('.linwiteditor-container');
+    // ele.addEventListener(
+    //   'mouseenter',
+    //   (e) => {
+    //     // console.log(e.target);
+    //     const ele = e.target;
+    //     console.log(ele.tagName);
+    //   },
+    //   true
+    // );
+  });
+});
+
+onUnmounted(() => {
+  aiEditor && aiEditor.destroy();
+});
+defineExpose({
+  getMarkDownContent,
+  getHTMLContent
+});
+</script>
+<style scoped>
+.editor {
+  position: relative;
+}
+
+:deep(.linwiteditor-container aie-footer > div span) {
+  display: none !important;
+}
+:deep(.linwiteditor-container aie-footer > div div) {
+  display: none !important;
+}
+:deep(.linwiteditor-container) {
+  border: none;
+}
+.ai-btn {
+  position: absolute;
+  top: -30px;
+  left: 0;
+  padding: 5px 10px;
+  font-size: 14px;
+  background-color: #007bff;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.ai-btn:hover {
+  background-color: #0056b3;
+}
+</style>

+ 1 - 1
src/modules/conversation-ai-editor/use-export-doc.js

@@ -760,7 +760,7 @@ export const ExportDoc = () => {
                 }
                 return _context.abrupt('return', blob);
               case 32:
-                saveAs(blob, options.fileName + '.doc');
+                saveAs(blob, options.fileName + '.docx');
               case 33:
               case 'end':
                 return _context.stop();

+ 2 - 2
src/modules/conversation-ai-editor/use-regex.js

@@ -2,11 +2,11 @@ export const getContentStr = (content) => {
   const regex = /<content>(.*?)<\/content>/;
   const match = content.match(regex);
   const contentText = match ? match : null;
-  return contentText[1] || '';
+  return contentText ? contentText[1] : content;
 };
 export const getContentType = (content) => {
   const regex = /<\/content>(.*)/;
   const match = content.match(regex);
   const contentText = match ? match : null;
-  return contentText[1] || '';
+  return contentText ? contentText[1] : content;
 };

+ 91 - 0
src/modules/knowledge/BaseShare.vue

@@ -0,0 +1,91 @@
+<template>
+  <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel">
+    <template #title> {{ $t('management.share') }} </template>
+    <div class="share-body">
+      <div class="share-title">{{ $t('management.share_way_tip') }}</div>
+      <div class="share-way">
+        <div class="way-item" v-for="item in way" :key="item.id">
+          <img :src="item.icon" alt="" />
+          <span>{{ item.name }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="share-body share-group">
+      <div class="share-title">{{ $t('management.team_member') }}</div>
+      <GroupTable></GroupTable>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { computed, ref } from 'vue';
+import shareLink from '../../assets/image/management/share-link.png';
+import qrCode from '../../assets/image/management/qr-code.png';
+import GroupTable from './baseShare/GroupTable.vue';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+const props = defineProps({
+  show_share: Boolean
+});
+
+const emit = defineEmits(['close']);
+const visible = computed(() => {
+  return props.show_share;
+});
+const way = computed(() => {
+  return [
+    {
+      id: 1,
+      name: t('management.copy_link'),
+      icon: shareLink
+    },
+    {
+      id: 2,
+      name: t('management.qr_code'),
+      icon: qrCode
+    }
+  ];
+});
+
+const handleCancel = () => {
+  emit('close');
+};
+const handleOk = () => {
+  emit('close');
+};
+</script>
+<style scoped>
+.share-body {
+}
+.share-title {
+  line-height: 24px;
+  font-size: 14px;
+  color: var(--color-text-title);
+  margin-bottom: 10px;
+}
+.share-way {
+  display: flex;
+  gap: 10px;
+  width: 100%;
+}
+.way-item {
+  flex: 1;
+  height: 94px;
+  border-radius: 12px;
+  background: var(--color-link-1);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  cursor: pointer;
+}
+.way-item:hover {
+  opacity: 0.8;
+}
+.share-group {
+  padding-top: 10px;
+}
+</style>

+ 28 - 3
src/modules/knowledge/MessageBody.vue

@@ -10,9 +10,16 @@
     >
       <template #bottom>
         <div class="bottom">
-          <div>{{ item.count }}&nbsp;{{ $t('management.document') }}</div>
-          <div>|</div>
-          <div>{{ item.time }}</div>
+          <div class="bottom-left">
+            <div>{{ item.count }}&nbsp;{{ $t('management.document') }}</div>
+            <div>|</div>
+            <div>{{ item.time }}</div>
+          </div>
+          <div class="bottom-right">
+            <a-tooltip :content="$t('management.share')">
+              <img class="icon" src="../../assets/image/management/share.png" alt="分享" @click.stop="toShare(item)" />
+            </a-tooltip>
+          </div>
         </div>
       </template>
       <template #settings>
@@ -33,6 +40,7 @@
   <a-spin class="init-loading" v-if="loading_data" :size="32" />
   <a-empty v-if="!moke_data.length"></a-empty>
   <DeleteModal :visible.sync="delete_visible" @ok="deleteModalOk" @cancel="delete_visible = false" />
+  <BaseShare v-if="show_share" :show_share="show_share" @close="show_share = false"></BaseShare>
 </template>
 
 <script setup>
@@ -41,6 +49,7 @@ import { Message } from '../../3rd-libs/arco-vue-libs';
 import { useRouter } from 'vue-router';
 import CardItem from '../common/CardItem.vue';
 import DeleteModal from '../../components/DeleteModal.vue';
+import BaseShare from './BaseShare.vue';
 import { getImageKnowLedge } from '../common/icon-map.js';
 import { funcThrottle } from '../../utils/utils';
 import { getKnowledgeList, deleteOwnKnowledge } from '../../apis/knowledge';
@@ -73,6 +82,8 @@ const search_text = ref('');
 // 删除弹窗
 const delete_visible = ref(false);
 const delete_data = ref(null);
+// 分享弹窗
+const show_share = ref(false);
 
 const handleToDetail = (item) => {
   router.push({
@@ -158,6 +169,10 @@ const editIconHandle = (item) => {
   bus_knowledgeIconEdit.emit(item);
 };
 
+const toShare = (item) => {
+  show_share.value = true;
+};
+
 bus_knowledgeSearch.on((text) => {
   search_text.value = text;
   moke_data.value = [];
@@ -194,6 +209,16 @@ onBeforeUnmount(() => {
 .bottom {
   display: flex;
   gap: 10px;
+  justify-content: space-between;
+}
+.bottom-left {
+  display: flex;
+  gap: 10px;
+}
+.bottom-right {
+  .icon {
+    cursor: pointer;
+  }
 }
 
 .loading-tips {

+ 93 - 0
src/modules/knowledge/baseShare/GroupTable.vue

@@ -0,0 +1,93 @@
+<template>
+  <a-table :columns="columns" :data="data">
+    <template #name="{ record }">
+      {{ record.owner ? record.name + '(我)' : record.name }}
+    </template>
+    <template #operate="{ record }">
+      <a-button type="text" v-if="record.owner" @click="handleClick(2)">{{ $t('management.table.transfer') }}</a-button>
+      <a-button type="text" v-if="!record.owner && record.status_code == 1" @click="handleClick(0)">{{
+        $t('management.table.forbidden')
+      }}</a-button>
+      <a-button type="text" status="danger" v-if="!record.owner && record.status_code == 2" @click="handleClick(1)">{{
+        $t('management.table.delete')
+      }}</a-button>
+    </template>
+  </a-table>
+  <ToolsModal v-if="show_modal" :show_modal="show_modal" :type="target_type" @close="closeToolsModal"></ToolsModal>
+</template>
+
+<script setup>
+import { ref, reactive, computed } from 'vue';
+import ToolsModal from './ToolsModal.vue';
+import { getStatus, getPermission } from './use_table_config';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+const columns = computed(() => {
+  return [
+    {
+      title: t('management.table.name'),
+      dataIndex: 'name',
+      slotName: 'name'
+    },
+    {
+      title: t('management.table.add_time'),
+      dataIndex: 'time',
+      slotName: 'time'
+    },
+    {
+      title: t('management.table.status'),
+      dataIndex: 'status',
+      slotName: 'status'
+    },
+    {
+      title: t('management.table.permission'),
+      dataIndex: 'permission',
+      slotName: 'permission'
+    },
+    {
+      title: t('management.table.operate'),
+      dataIndex: 'operate',
+      slotName: 'operate'
+    }
+  ];
+});
+const data = reactive([
+  {
+    key: '1',
+    name: '张三',
+    time: '2025-02.12',
+    status_code: 1,
+    status: getStatus(1),
+    permission: getPermission(1),
+    owner: 1
+  },
+  {
+    key: '1',
+    name: '张三',
+    time: '2025-02.12',
+    status_code: 2,
+    status: getStatus(2),
+    permission: getPermission(2)
+  },
+  {
+    key: '1',
+    name: '张三',
+    time: '2025-02.12',
+    status_code: 1,
+    status: getStatus(1),
+    permission: getPermission(1)
+  }
+]);
+
+const show_modal = ref(false);
+const target_type = ref(0);
+const handleClick = (type) => {
+  target_type.value = type;
+  show_modal.value = true;
+};
+const closeToolsModal = () => {
+  show_modal.value = false;
+};
+</script>
+<style scoped></style>

+ 81 - 0
src/modules/knowledge/baseShare/ToolsModal.vue

@@ -0,0 +1,81 @@
+<template>
+  <a-modal v-model:visible="visible" :width="400" @ok="handleOk" @cancel="handleCancel">
+    <template #title> {{ target_config.title }} </template>
+    <div class="body">
+      <div class="item">{{ target_config.desc }}</div>
+      <div class="group" v-if="target_config.persons">
+        <div class="label">{{ $t('management.table.member_select') }}:</div>
+        <a-select v-model="current_person" :placeholder="$t('management.table.member_select')">
+          <a-option v-for="item in target_config.persons" :key="item.id">{{ item.name }}</a-option>
+        </a-select>
+      </div>
+    </div>
+  </a-modal>
+</template>
+<script setup>
+import { ref, computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
+
+const props = defineProps({
+  show_modal: Boolean,
+  type: Number,
+  persons: {
+    type: Array,
+    default: () => {
+      return [
+        {
+          id: 1,
+          name: '李四'
+        }
+      ];
+    }
+  }
+});
+const emit = defineEmits(['close']);
+
+const visible = computed(() => {
+  return props.show_modal;
+});
+const config = computed(() => {
+  return [
+    {
+      title: t('management.table.forbidden'),
+      desc: t('management.table.forbidden_tips')
+    },
+    {
+      title: t('management.table.delete'),
+      desc: t('management.table.delete_tips')
+    },
+    {
+      title: t('management.table.transfer'),
+      desc: t('management.table.transfer_tips'),
+      persons: props.persons
+    }
+  ];
+});
+const target_config = computed(() => {
+  return config.value[props.type];
+});
+
+const handleOk = () => {};
+const handleCancel = () => {
+  emit('close');
+};
+</script>
+<style scoped>
+.body {
+  /* color: #3e3f40; */
+}
+.group {
+  margin-top: 10px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  .label {
+    min-width: 80px;
+    text-align: right;
+  }
+}
+</style>

+ 16 - 0
src/modules/knowledge/baseShare/use_table_config.js

@@ -0,0 +1,16 @@
+const status = {
+  1: '正常',
+  2: '禁用'
+};
+
+const permissions = {
+  1: '管理',
+  2: '仅使用'
+};
+
+export const getStatus = (key) => {
+  return status[key] || '未知';
+};
+export const getPermission = (key) => {
+  return permissions[key] || '未知';
+};

+ 1 - 0
src/views/conversation/ConversationChatContainer.vue

@@ -1367,6 +1367,7 @@ const sseOnMessage = (ev) => {
   if (res_data.message_id) {
     minMap_messageId.value = res_data.message_id;
   }
+
   //sse流式结束
   if (res_data.event === 'message_end') {
     stopStream();

+ 2 - 2
vite.config.mjs

@@ -34,10 +34,10 @@ export default defineConfig(({ mode }) => {
       host: '0.0.0.0', // IP配置,支持从IP启动
       proxy: {
         '/api/': {
-          target: 'http://smartai.com:8401',
+          // target: 'http://smartai.com:8401',
 
           // target: 'http://192.168.20.119:9201',
-          // target: 'http://smartai.com:8164',
+          target: 'http://smartai.com:8164',
           changeOrigin: true,
           secure: false,
           ws: true,

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików