Pārlūkot izejas kodu

feat(智能体管理):默认智能体弹窗,智能体创建弹窗,图标替换弹窗

hanyang 1 gadu atpakaļ
vecāks
revīzija
09f1e09948

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

@@ -87,6 +87,7 @@
     "history_month": "This month",
     "history_earlier": "Earlier",
     "history_loadmore": "Load more",
+    "history_nomore": "No more",
     "history_empty": "Empty"
   }
 }

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

@@ -87,6 +87,7 @@
     "history_month": "本月",
     "history_earlier": "更早以前",
     "history_loadmore": "加载更多",
+    "history_nomore": "没有更多了",
     "history_empty": "暂无数据"
   }
 }

BIN
src/assets/header-agent-2.png


BIN
src/assets/header-huihua-2.png


BIN
src/assets/header-moxingguanli-2.png


BIN
src/assets/header-quanxian-2.png


BIN
src/assets/header-zhinengti-2.png


BIN
src/assets/header-zhishiku-2.png


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


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


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


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


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


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


+ 27 - 0
src/base/store/use-all-agents.js

@@ -0,0 +1,27 @@
+import { defineStore } from 'pinia';
+import { jsonStringify, jsonParse } from '../../utils/utils';
+
+/**
+ * 系统所有可用的agents列表
+ */
+export const useAllAgentStore = defineStore('all_agents', {
+  state: () => {
+    return {
+      agents: []
+    };
+  },
+  actions: {
+    /**
+     * 获取所有的记录
+     * @returns
+     */
+    getList() {
+      return this.agents;
+    },
+    setList(arr) {
+      const list = jsonParse(jsonStringify(arr));
+
+      this.agents = list;
+    }
+  }
+});

+ 13 - 3
src/modules/conversation-board/BoardAgentItem.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="conversation-agent-item">
-    <div class="agent-item-icon"></div>
+    <div class="agent-item-icon" @click="handleClick"></div>
 
-    <div class="agent-item-intro">
+    <div class="agent-item-intro" @click="handleClick">
       <div class="agent-item-intro-title">{{ title }}</div>
       <div class="agent-item-intro-desc">{{ desc }}</div>
     </div>
@@ -12,8 +12,15 @@
 <script setup>
 const props = defineProps({
   title: String,
-  desc: String
+  desc: String,
+  id: String
 });
+
+const emit = defineEmits(['active']);
+
+const handleClick = () => {
+  emit('active', props.id);
+};
 </script>
 
 <style lang="css" scoped>
@@ -35,9 +42,12 @@ const props = defineProps({
   border-radius: 18px;
 
   margin-right: 5px;
+
+  cursor: pointer;
 }
 
 .agent-item-intro {
+  cursor: pointer;
 }
 
 .agent-item-intro-title {

+ 68 - 51
src/modules/conversation-board/BoardAgentList.vue

@@ -1,62 +1,79 @@
 <template>
   <div class="conversation-agent-list">
-    <BoardAgentItem v-for="(item, index) of list" :key="index" :title="item.title" :desc="item.desc" />
+    <BoardAgentItem
+      v-for="(item, index) of list"
+      :key="index"
+      :title="item.name"
+      :desc="item.type"
+      :id="item.id"
+      @active="handleActive"
+    />
   </div>
 </template>
 
 <script setup>
 import BoardAgentItem from './BoardAgentItem.vue';
 
-const list = [
-  {
-    title: '智能问答',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '智能客服',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '出题组卷',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '以文生图',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '数据分析',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '报告自动生成',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '智能问答',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '文档创作',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '设备检测',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '智能客服',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '以文生图',
-    desc: '你说一句话,我写万字长文'
-  },
-  {
-    title: '出题组卷',
-    desc: '你说一句话,我写万字长文'
-  }
-];
+const props = defineProps({
+  list: Array
+});
+
+const emit = defineEmits(['itemActive']);
+
+// const list = [
+//   {
+//     title: '智能问答',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '智能客服',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '出题组卷',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '以文生图',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '数据分析',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '报告自动生成',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '智能问答',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '文档创作',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '设备检测',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '智能客服',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '以文生图',
+//     desc: '你说一句话,我写万字长文'
+//   },
+//   {
+//     title: '出题组卷',
+//     desc: '你说一句话,我写万字长文'
+//   }
+// ];
+
+const handleActive = (target_id) => {
+  emit('itemActive', target_id);
+};
 </script>
 
 <style lang="css" scoped>

+ 13 - 6
src/modules/conversation-board/BoardTags.vue

@@ -4,12 +4,6 @@
     <div class="board-tag" @click="handleClick"><span>会话</span></div>
     <div class="board-tag" @click="handleClick"><span>知识库管理</span></div>
     <div class="board-tag" @click="handleClick"><span>AI会话</span></div>
-
-    <!-- <a-space>
-      <a-tag>Default</a-tag>
-      <a-tag>Tag 1</a-tag>
-      <a-tag>Tag 2</a-tag>
-    </a-space> -->
   </div>
 </template>
 
@@ -30,5 +24,18 @@ const handleClick = (type) => {
 }
 
 .conversation-board-tags .board-tag {
+  margin-left: 5px;
+  margin-right: 5px;
+
+  cursor: pointer;
+
+  padding: 10px;
+  padding-left: 16px;
+  padding-right: 16px;
+
+  border-radius: 8px;
+
+  background-color: var(--color-bg-1);
+  color: var(--color-text-1);
 }
 </style>

+ 76 - 1
src/modules/conversation-board/api-conversation-board.js

@@ -1,6 +1,81 @@
 import { jsonStringify } from '../../utils/utils';
 
+const res_list_example = {
+  code: 200,
+  msg: '',
+  data: [
+    {
+      id: '94873c72-d194-4306-a965-286affe426bf',
+      name: '报告生成',
+      agent_type: 2,
+      type: 'report'
+    },
+    {
+      id: 'basic_excel_merge',
+      name: '报表合并',
+      agent_type: 3,
+      type: 'excelMerge'
+    },
+    {
+      id: '42e4fcdc9bea11efac300242ac160006',
+      name: '知识问答',
+      agent_type: 1,
+      type: 'knowledgeQA'
+    },
+    {
+      id: 'c684bab4-f05b-423e-8727-f50497e73ebf',
+      name: '文档智能',
+      agent_type: 2,
+      type: 'report'
+    },
+    {
+      id: '90d533729c0211efbf6b0242ac160006',
+      name: '智能问答',
+      agent_type: 1,
+      type: 'chat'
+    },
+    {
+      id: 'basic_excel_talk',
+      name: '智能数据',
+      agent_type: 3,
+      type: 'excelTalk'
+    },
+    {
+      id: 'basic_question_talk',
+      name: '出题组卷',
+      agent_type: 3,
+      type: 'questionTalk'
+    },
+    {
+      id: '9d75142a-66eb-4e23-b7d4-03efe4584915',
+      name: '小数绘图',
+      agent_type: 4,
+      type: 'imageTalk'
+    },
+    {
+      id: 'basic_paper_talk',
+      name: '文档出卷',
+      agent_type: 3,
+      type: 'paperTalk'
+    },
+    {
+      id: 'basic_report_clean',
+      name: '文档报告',
+      agent_type: 4,
+      type: 'reportWorkflow'
+    }
+  ]
+};
+
 /**
  * 获取所有对话可用的智能体
  */
-export const conversationBoardList = () => {};
+export const conversationBoardList = () => {
+  // http://192.168.20.119:9301/api/agent/list
+
+  return new Promise((resolve, reject) => {
+    setTimeout(() => {
+      resolve(res_list_example);
+    }, 1000);
+  });
+};

+ 0 - 21
src/modules/conversation-chat/ChatName.vue

@@ -1,21 +0,0 @@
-<template>
-  <div class="conversation-history-title">
-    <div>{{ $t('conversation.chat_history') }}</div>
-  </div>
-</template>
-
-<script setup></script>
-
-<style lang="css" scoped>
-.conversation-history-title {
-  margin-top: 30px;
-  margin-bottom: 30px;
-
-  text-align: center;
-
-  font-size: 32px;
-  font-weight: bold;
-
-  color: var(--color-text-1);
-}
-</style>

+ 59 - 0
src/modules/intelligent/CardDefault.vue

@@ -0,0 +1,59 @@
+<template>
+  <div class="card-default">
+    <div class="header">
+      <img class="icon" :src="img_src" alt="" />
+      <div class="title">{{ name }}</div>
+    </div>
+    <div class="section">
+      <div>{{ description }}</div>
+      <div class="labels">{{ labels }}</div>
+    </div>
+    <div class="footer">
+      <slot name="footer"></slot>
+    </div>
+  </div>
+</template>
+
+<script setup>
+const props = defineProps({
+  name: {
+    type: String,
+    default: '问答助理',
+    required: true
+  },
+  img_src: {
+    type: String,
+    default: '../../assets/image/management/intelligent-frame1.png'
+  },
+  description: {
+    type: String,
+    default: 'EMBEDDING,SPEECH2TEXT,MODERATION'
+  },
+  labels: {
+    type: String,
+    default: 'LLM,TEXT'
+  }
+});
+</script>
+<style scoped lang="css">
+.card-default {
+  border: 1px solid var(--color-neutral-3);
+  padding: 20px;
+}
+.header {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+}
+.header .icon {
+  width: 44px;
+}
+.header .title {
+  font-size: 16px;
+  font-weight: bold;
+}
+.section {
+  margin: 20px 0;
+  color: var(--color-neutral-6);
+}
+</style>

+ 0 - 1
src/modules/intelligent/ManageTags.vue

@@ -76,7 +76,6 @@ const handleDelete = (tag) => {
   tags.value = tags.value.filter((t) => t.name !== tag.name);
 };
 const handleCancel = () => {
-  i;
   emit('update:visible', false);
 };
 

+ 18 - 1
src/modules/intelligent/MessageBody.vue

@@ -26,9 +26,13 @@
       <template #bottom>
         <div class="bottom">
           <div class="user"><icon-user /> {{ $t('management.createUser') }}:{{ item.user }}</div>
-          <div class="tools">
+          <div class="tools" v-if="item.online">
             <icon-more :style="{ fontSize: '20px' }" />
           </div>
+          <div class="tools" v-if="!item.online">
+            <icon-settings :style="{ fontSize: '20px', cursor: 'pointer' }" @click="editIntelligent" />
+            <icon-delete :style="{ fontSize: '20px', cursor: 'pointer' }" @click="deleteIntelligent" />
+          </div>
         </div>
       </template>
     </CardItem>
@@ -104,6 +108,15 @@ const scrollHandler = (e) => {
 const openManageTags = () => {
   visible.value = true;
 };
+
+const editIntelligent = () => {
+  // TODO:微前端执行编辑页面
+  console.log('editIntelligent');
+};
+const deleteIntelligent = () => {
+  console.log('deleteIntelligent');
+};
+
 bus_intelligentSearch.on((text) => {
   search_text.value = text;
   moke_data.value = [];
@@ -156,4 +169,8 @@ onBeforeUnmount(() => {
   grid-row-start: auto;
   text-align: center;
 }
+.tools {
+  display: flex;
+  gap: 5px;
+}
 </style>

+ 79 - 0
src/modules/intelligent/ModalAddIntel.vue

@@ -0,0 +1,79 @@
+<template>
+  <a-modal
+    v-model:visible="showModal"
+    title-align="start"
+    :align-center="false"
+    :esc-to-close="false"
+    :footer="false"
+    top="15vh"
+    width="60vw"
+    @before-cancel="handleCancel"
+  >
+    <template #title>
+      <div class="model-title">新建智能体</div>
+    </template>
+    <div class="section">
+      <CardDefault
+        v-for="item in default_intelligent"
+        :key="item.name"
+        :name="item.name"
+        :description="item.description"
+        :labels="item.labels"
+      >
+        <template #footer>
+          <a-button class="add-btn" @click="addNewIntelligent(item)"> <icon-plus /> 新建 </a-button>
+        </template>
+      </CardDefault>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+import CardDefault from './CardDefault.vue';
+import { getDefaultIntelligent } from '../../views/manage/common';
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  }
+});
+const emit = defineEmits(['update:visible']);
+
+const showModal = computed(() => props.visible);
+
+const default_intelligent = getDefaultIntelligent();
+
+const handleCancel = () => {
+  emit('update:visible', false);
+};
+
+const addNewIntelligent = (item) => {
+  // TODO: 根据item中的type区分新建智能体的类型
+  emit('update:visible', false);
+  emit('add-intelligent', item);
+};
+</script>
+<style scoped lang="css">
+.model-title {
+  font-size: 16px;
+  font-weight: bold;
+}
+.section {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  justify-content: flex-start;
+  gap: 20px 20px;
+}
+.section .add-btn {
+  width: 100%;
+}
+.section .add-btn:hover {
+  background-color: rgb(var(--arcoblue-6));
+  color: var(--color-bg-1);
+}
+.arco-form-item-content-wrapper {
+  border-color: var(--color-neutral-4);
+}
+</style>

+ 0 - 52
src/modules/intelligent/ModalItem.vue

@@ -1,52 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="showModal"
-    title="添加智能体"
-    title-align="start"
-    :align-center="false"
-    top="15vh"
-    @cancel="handleCancel"
-    @before-ok="handleBeforeOk"
-  >
-    <a-form :model="form">
-      <a-form-item field="name" label="名称" validate-trigger="input" required>
-        <a-input v-model="form.name" placeholder="请输入名称" />
-      </a-form-item>
-    </a-form>
-  </a-modal>
-</template>
-
-<script setup>
-import { ref, computed } from 'vue';
-
-const props = defineProps({
-  visible: {
-    type: Boolean,
-    default: false
-  }
-});
-
-const emit = defineEmits(['update:visible']);
-
-const form = ref({
-  name: ''
-});
-const showModal = computed(() => props.visible);
-const handleBeforeOk = (done) => {
-  if (form.value.name.trim().length) {
-    // TODO:添加智能体
-    done();
-  } else {
-    return false;
-  }
-};
-const handleCancel = () => {
-  form.value.name = '';
-  emit('update:visible', false);
-};
-</script>
-<style scoped lang="css">
-.arco-form-item-content-wrapper {
-  border-color: var(--color-neutral-4);
-}
-</style>

+ 119 - 0
src/modules/intelligent/ModalSelectIcon.vue

@@ -0,0 +1,119 @@
+<template>
+  <a-modal
+    v-model:visible="showModal"
+    :align-center="false"
+    top="15vh"
+    @cancel="handleCancel"
+    @before-ok="handleBeforeOk"
+  >
+    <template #title>替换图标</template>
+    <div class="section">
+      <div class="labels">全部图标</div>
+      <div class="icons">
+        <div
+          class="icon-border"
+          v-for="icon in icons"
+          :key="icon.icon"
+          :class="{ 'icon-border-active': icon.id === target_icon }"
+          @click="changeItem(icon.id)"
+        >
+          <img class="icon" :src="icon.icon" alt="" />
+        </div>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+import intellFrame1 from '../../assets/image/management/intellFrame1.png';
+import intellFrame2 from '../../assets/image/management/intellFrame2.png';
+import intellFrame3 from '../../assets/image/management/intellFrame3.png';
+import intellFrame4 from '../../assets/image/management/intellFrame4.png';
+import intellFrame5 from '../../assets/image/management/intellFrame5.png';
+import intellFrame6 from '../../assets/image/management/intellFrame6.png';
+
+const props = defineProps({
+  show_select_icon: {
+    type: Boolean,
+    default: false
+  }
+});
+const icons = ref([
+  {
+    id: 1,
+    icon: intellFrame1
+  },
+  {
+    id: 2,
+    icon: intellFrame2
+  },
+  {
+    id: 3,
+    icon: intellFrame3
+  },
+  {
+    id: 4,
+    icon: intellFrame4
+  },
+  {
+    id: 5,
+    icon: intellFrame5
+  },
+  {
+    id: 6,
+    icon: intellFrame6
+  }
+]);
+
+const target_icon = ref(icons.value[0].id);
+const emit = defineEmits(['update:show_model_item', 'sendIcon']);
+
+const showModal = computed(() => props.show_select_icon);
+
+const changeItem = (id) => {
+  target_icon.value = id;
+};
+const handleBeforeOk = (done) => {
+  emit('sendIcon', icons.value.filter((icon) => icon.id === target_icon.value)[0].icon);
+  emit('update:show_select_icon', false);
+  done();
+};
+const handleCancel = () => {
+  emit('update:show_select_icon', false);
+};
+</script>
+<style scoped lang="css">
+.section {
+  height: 200px;
+  padding: 0 20px;
+}
+.icons {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  margin-top: 10px;
+}
+.icons .icon-border {
+  /* width: 50px;
+  height: 50px; */
+  padding: 5px 10px;
+  cursor: pointer;
+}
+.icon-border:hover {
+  border: 1px solid var(--color-neutral-4);
+  border-radius: 5px;
+}
+.icon-border .icon {
+  width: 44px;
+  height: 44px;
+}
+.icon-border-active {
+  border: 1px solid var(--color-neutral-4);
+  border-radius: 5px;
+}
+.arco-input-wrapper {
+  height: 32px;
+  background-color: var(--color-neutral-3);
+}
+</style>

+ 79 - 0
src/modules/intelligent/ModelAddItem.vue

@@ -0,0 +1,79 @@
+<template>
+  <a-modal
+    v-model:visible="showModal"
+    :align-center="false"
+    top="15vh"
+    @cancel="handleCancel"
+    @before-ok="handleBeforeOk"
+  >
+    <template #title> 新建 </template>
+    <div class="section">
+      <div class="form-item">
+        <div class="label">图标&名称</div>
+        <div class="value">
+          <img class="icon" :src="target_icon" alt="" @click="handleSelectIcon" />
+          <a-input v-model:value="form.name" placeholder="请输入名称" />
+        </div>
+      </div>
+      <div class="form-item">
+        <div class="label">描述</div>
+        <a-input v-model:value="form.description" placeholder="请输入名称" />
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+
+const props = defineProps({
+  show_model_item: {
+    type: Boolean,
+    default: false
+  },
+  target_icon: {
+    type: String,
+    default: '../../assets/image/management/intelligent-frame1.png'
+  }
+});
+const form = ref({
+  name: '',
+  description: ''
+});
+
+const emit = defineEmits(['update:show_model_item', 'select_icon']);
+
+const showModal = computed(() => props.show_model_item);
+const handleBeforeOk = (done) => {};
+const handleCancel = () => {
+  form.value.name = '';
+  emit('update:show_model_item', false);
+};
+const handleSelectIcon = () => {
+  emit('select_icon');
+};
+</script>
+<style scoped lang="css">
+.section {
+  padding: 0 20px;
+}
+.form-item {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  margin-top: 20px;
+}
+.value {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.value .icon {
+  width: 44px;
+  cursor: pointer;
+}
+.arco-input-wrapper {
+  height: 32px;
+  background-color: var(--color-neutral-3);
+}
+</style>

+ 24 - 2
src/modules/intelligent/TopSetting.vue

@@ -18,17 +18,28 @@
       {{ $t('management.createIntelligent') }}
     </a-button>
   </a-space>
-  <ModalItem v-model:visible="visible"></ModalItem>
+  <ModalAddIntel v-model:visible="visible" @add-intelligent="addIntelligent"></ModalAddIntel>
+  <ModelAddItem
+    v-model:show_model_item="show_model_item"
+    :target_icon="target_icon"
+    @select_icon="selectIcon"
+  ></ModelAddItem>
+  <ModelSelectIcon v-model:show_select_icon="show_select_icon" @sendIcon="sendIcon"></ModelSelectIcon>
 </template>
 
 <script setup>
 import { ref } from 'vue';
-import ModalItem from './ModalItem.vue';
+import ModalAddIntel from './ModalAddIntel.vue';
+import ModelAddItem from './ModelAddItem.vue';
+import ModelSelectIcon from './ModalSelectIcon.vue';
 import { funcDebounce } from '../../utils/utils';
 import { bus_intelligentSearch } from '../../base/event-bus';
 
 const searchText = ref('');
 const visible = ref(false);
+const show_model_item = ref(false);
+const show_select_icon = ref(false);
+const target_icon = ref('../../assets/image/management/intelligent-frame1.png');
 // 搜索
 const handleSearch = funcDebounce(
   () => {
@@ -41,6 +52,17 @@ const handleSearch = funcDebounce(
 const handleCreate = () => {
   visible.value = true;
 };
+
+const addIntelligent = (data) => {
+  show_model_item.value = true;
+};
+const selectIcon = () => {
+  show_select_icon.value = true;
+};
+const sendIcon = (icon) => {
+  console.log('sendIcon', icon);
+  target_icon.value = icon;
+};
 </script>
 <style scoped lang="scss"></style>
 <style>

+ 32 - 0
src/views/manage/common.js

@@ -38,3 +38,35 @@ export const getImageKnowLedge = (avatar) => {
 export const getImageIntelligent = (avatar) => {
   return image_intelligent_map[avatar] || intelligentFrame1;
 };
+
+/**
+ * @description: 默认智能体数据
+ */
+export const getDefaultIntelligent = () => {
+  return [
+    {
+      name: '问答助理',
+      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
+      labels: 'LLM,TEXT',
+      type: 'QA'
+    },
+    {
+      name: '工作流助手',
+      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
+      labels: 'LLM,TEXT',
+      type: 'ZS'
+    },
+    {
+      name: '智能Agent',
+      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
+      labels: 'LLM,TEXT',
+      type: 'AG'
+    },
+    {
+      name: '工作流应用',
+      description: 'EMBEDDING,SPEECH2TEXT,MODERATION',
+      labels: 'LLM,TEXT',
+      type: 'YY'
+    }
+  ];
+};