Newer
Older
dxCard-admin / src / views / super / airag / aiknowledge / AiKnowledgeBaseList.vue
YFJ on 23 Sep 13 KB 项目推送
<!--知识库添加页面-->
<template>
  <div class="knowledge">
    <!--查询区域-->
    <div class="jeecg-basic-table-form-container">
      <a-form
        ref="formRef"
        @keyup.enter.native="searchQuery"
        :model="queryParam"
        :label-col="labelCol"
        :wrapper-col="wrapperCol"
        style="background-color: #f7f8fc"
      >
        <a-row :gutter="24">
          <a-col :xl="7" :lg="7" :md="8" :sm="24">
            <a-form-item name="name" label="知识库名称">
              <JInput v-model:value="queryParam.name" placeholder="请输入知识库名称" />
            </a-form-item>
          </a-col>
          <a-col :xl="6" :lg="7" :md="8" :sm="24">
            <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
              <a-col :lg="6">
                <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
                <a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
              </a-col>
            </span>
          </a-col>
        </a-row>
      </a-form>
    </div>

    <a-row :span="24" class="knowledge-row">
      <a-col :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24">
        <a-card class="add-knowledge-card" @click="handleAddKnowled">
          <div class="flex">
            <Icon icon="ant-design:plus-outlined" class="add-knowledge-card-icon" size="20"></Icon>
            <span class="add-knowledge-card-title">创建知识库</span>
          </div>
        </a-card>
      </a-col>
      <a-col v-if="knowledgeList && knowledgeList.length>0" :xxl="4" :xl="6" :lg="6" :md="6" :sm="12" :xs="24" v-for="item in knowledgeList">
        <a-card class="knowledge-card pointer" @click="handleDocClick(item.id)">
          <div class="knowledge-header">
            <div class="flex">
              <img class="header-img" src="./icon/knowledge.png" />
              <div class="header-text">
                <span class="header-text-top header-name ellipsis" :title="item.name"> {{ item.name }} </span>
                <span class="header-text-top"> 创建者:{{ item.createBy_dictText || item.createBy }} </span>
              </div>
            </div>
          </div>
          <div class="mt-10 text-desc">
            <span>{{ item.descr || '暂无描述' }}</span>
          </div>
          <div class="knowledge-footer">
            <Icon class="knowledge-footer-icon" icon="ant-design:deployment-unit-outlined" size="14"></Icon>
            <span>{{ item.embedId_dictText }}</span>
          </div>
          <div class="knowledge-btn">
            <a-dropdown placement="bottomRight" :trigger="['click']" :getPopupContainer="(node) => node.parentNode">
              <div class="ant-dropdown-link pointer model-icon" @click.prevent.stop>
                <Icon icon="ant-design:ellipsis-outlined" size="16"></Icon>
              </div>
              <template #overlay>
                <a-menu>
                  <a-menu-item key="vectorization" @click.prevent.stop="handleVectorization(item.id)">
                    <Icon icon="ant-design:retweet-outlined" size="16"></Icon>
                    向量化
                  </a-menu-item>
                  <a-menu-item key="text" @click.prevent.stop="handleEditClick(item)">
                    <Icon class="pointer" icon="ant-design:edit-outlined" size="16"></Icon>
                    编辑
                  </a-menu-item>
                  <a-menu-item key="file" @click.prevent.stop="handleDelete(item)">
                    <Icon class="pointer" icon="ant-design:delete-outlined" size="16"></Icon>
                    删除
                  </a-menu-item>
                  <a-menu-item key="clear" @click.prevent.stop="onDeleteAllDoc(item)">
                    <Icon icon="ant-design:delete-outlined" size="16"></Icon>
                    清空文档
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </div>
        </a-card>
      </a-col>
    </a-row>
    <Pagination
      v-if="knowledgeList.length > 0"
      :current="pageNo"
      :page-size="pageSize"
      :page-size-options="pageSizeOptions"
      :total="total"
      :showQuickJumper="true"
      :showSizeChanger="true"
      @change="handlePageChange"
      class="list-footer"
      size="small"
      :show-total="() => `共${total}条` "
    />
    <!--添加知识库弹窗-->
    <KnowledgeBaseModal @register="registerModal" @success="reload"></KnowledgeBaseModal>
    <!-- 知识库文档弹窗 -->
    <AiragKnowledgeDocListModal @register="docListRegister"></AiragKnowledgeDocListModal>
  </div>
</template>

<script lang="ts">
  import { reactive, ref } from 'vue';
  import { useModal } from '/@/components/Modal';
  import { deleteModel, list, rebuild } from './AiKnowledgeBase.api';
  import { doDeleteAllDoc } from "./AiKnowledgeBase.api.util";
  import { Pagination } from 'ant-design-vue';
  import JInput from '@/components/Form/src/jeecg/components/JInput.vue';
  import KnowledgeBaseModal from './components/AiKnowledgeBaseModal.vue';
  import JSelectUser from '@/components/Form/src/jeecg/components/JSelectUser.vue';
  import JDictSelectTag from '@/components/Form/src/jeecg/components/JDictSelectTag.vue';
  import AiragKnowledgeDocListModal from './components/AiragKnowledgeDocListModal.vue';
  import Icon from '@/components/Icon';
  import { useMessage } from "@/hooks/web/useMessage";

  export default {
    name: 'KnowledgeBaseList',
    components: {
      Icon,
      AiragKnowledgeDocListModal,
      KnowledgeBaseModal,
      JDictSelectTag,
      JSelectUser,
      JInput,
      Pagination,
    },
    setup() {
      //模型列表
      const knowledgeList = ref([]);

      //注册modal
      const [registerModal, { openModal }] = useModal();
      const [docListRegister, { openModal: openDocModal }] = useModal();

      //当前页数
      const pageNo = ref<number>(1);
      //每页条数
      const pageSize = ref<number>(10);
      //总条数
      const total = ref<number>(0);
      //可选择的页数
      const pageSizeOptions = ref<any>(['10', '20', '30']);
      //查询参数
      const queryParam = reactive<any>({});
      //查询区域label宽度
      const labelCol = reactive({
        xs: 24,
        sm: 4,
        xl: 6,
        xxl: 6,
      });
      //查询区域组件宽度
      const wrapperCol = reactive({
        xs: 24,
        sm: 20,
      });
      //查询区域表单的ref
      const formRef = ref();
      const { createMessage } = useMessage();

      //页面初始化执行列表查询
      reload();

      /**
       * 新增
       */
      async function handleAddKnowled() {
        openModal(true, {});
      }

      /**
       * 编辑
       *
       * @param item
       */
      function handleEditClick(item) {
        console.log(item);
        openModal(true, {
          id: item.id,
          isUpdate: true,
        });
      }

      /**
       * 重新加载数据
       */
      function reload() {
        let params = {
          pageNo: pageNo.value,
          pageSize: pageSize.value,
          column: 'createTime',
          order: 'desc'
        };
        Object.assign(params, queryParam);
      
        list(params).then((res) => {
          if (res.success) {
            knowledgeList.value = res.result.records;
            total.value = res.result.total;
          } else {
            knowledgeList.value = [];
            total.value = 0;
          }
        });
      }

      /**
       * 分页改变事件
       * @param page
       * @param current
       */
      function handlePageChange(page, current) {
        pageNo.value = page;
        pageSize.value = current;
        reload();
      }

      /**
       * 删除模型
       * @param item
       */
      async function handleDelete(item) {
        if(knowledgeList.value.length == 1 && pageNo.value > 1) {
          pageNo.value = pageNo.value - 1;
        }
        await deleteModel({ id: item.id, name: item.name }, reload);
      }

      /**
       * 清空文档
       * @param item
       */
      async function onDeleteAllDoc(item) {
        pageNo.value = 1;
        return doDeleteAllDoc(item.id, reload);
      }

      /**
       * 查询
       */
      function searchQuery() {
        pageNo.value = 1;
        reload();
      }

      /**
       * 重置
       */
      function searchReset() {
        formRef.value.resetFields();
        queryParam.createBy = '';
        pageNo.value = 1;
        //刷新数据
        reload();
      }

      /**
       * 参数配置点击事件
       *
       * @param id
       */
      function handleDocClick(id) {
        openDocModal(true, { id });
      }

      /**
       * 知识库向量化
       * @param id
       */
      async function handleVectorization(id) {
        rebuild({ knowIds: id }).then((res) =>{
          if(res.success){
            createMessage.success("向量化成功!");
            reload();
          }else{
            createMessage.warning("向量化失败!");
          }
        }).catch(err=>{
          createMessage.warning("向量化失败!");
        });
      }

      return {
        handleAddKnowled,
        handleEditClick,
        registerModal,
        knowledgeList,
        reload,
        pageNo,
        pageSize,
        pageSizeOptions,
        total,
        handlePageChange,
        handleDelete,
        onDeleteAllDoc,
        searchQuery,
        searchReset,
        queryParam,
        labelCol,
        wrapperCol,
        formRef,
        handleDocClick,
        docListRegister,
        handleVectorization,
      };
    },
  };
</script>

<style scoped lang="less">
  .knowledge {
    height: calc(100vh - 115px);
    background: #f7f8fc;
    padding: 24px;
    overflow-y: auto;

    .knowledge-row {
      max-height: calc(100% - 100px);
      margin-top: 20px;
      overflow-y: auto;
      .knowledge-header {
        position: relative;
        font-size: 14px;
        height: 40px;
        .header-img {
          width: 34px;
          height: 34px;
          margin-right: 6px;
        }
        .header-text {
          width: calc(100% - 80px);
          overflow: hidden;
          position: relative;
          display: grid;
          .header-name {
            font-size: 14px !important;
            font-weight: bold;
            color: #354052 !important;
          }
          .header-text-top {
            height: 22px;
            font-size: 12px;
          }
        }
      }
    }
  }

  .text-desc {
    width: 100%;
    font-weight: 400;
    display: inline-block;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    height: 40px;
    overflow: hidden;
    font-size: 12px;
    color: #676f83;
  }
  
  .knowledge-footer{
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: 16px;
    .knowledge-footer-icon{
      position: relative;
      top: 2px
    }
    span{
      margin-left: 2px;
    }
  }

  .flex {
    display: flex;
    align-items: center;
  }

  :deep(.ant-card .ant-card-body) {
    padding: 16px;
  }

  .mt-10 {
    margin-top: 10px;
  }

  .ml-4 {
    margin-left: 4px;
  }

  .knowledge-btn {
    position: absolute;
    right: 4px;
    top: 6px;
    height: auto;
    display: none;
  }
  .add-knowledge-card {
    margin-bottom: 20px;
    background: #fcfcfd;
    border: 1px solid #f0f0f0;
    box-shadow: 0 2px 4px #e6e6e6;
    transition: all 0.3s ease;
    border-radius: 10px;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    font-size: 16px;
    cursor: pointer;
    height: 152px;
    width: calc(100% - 20px);
    .add-knowledge-card-icon {
      padding: 8px;
      color: #1f2329;
      background-color: #f5f6f7;
      margin-right: 12px;
    }
    .add-knowledge-card-title {
      font-size: 16px;
      color:#1f2329;
      font-weight: 400;
      align-self: center;
    }
  }

  .add-knowledge-card:hover {
    box-shadow: 0 6px 12px #d0d3d8;
  }

  .knowledge-card {
    margin-right: 20px;
    margin-bottom: 20px;
    height: 152px;
    border-radius: 10px;
    background: #fcfcfd;
    border: 1px solid #f0f0f0;
    box-shadow: 0 2px 4px #e6e6e6;
    transition: all 0.3s ease;
  }
  .knowledge-card:hover {
    box-shadow: 0 6px 12px #d0d3d8;
    .knowledge-btn {
      display: block;
    }
  }
  .pointer {
    cursor: pointer;
  }
  .list-footer {
    text-align: right;
    margin-top: 5px;
  }
  .jeecg-basic-table-form-container {
    padding: 0;
    :deep(.ant-form) {
      background-color: transparent;
    }
    .table-page-search-submitButtons {
      display: block;
      margin-bottom: 24px;
      white-space: nowrap;
    }
  }
  
  .model-icon{
    background-color: unset;
    border: none;
    margin-right: 2px;
  }
  .model-icon:hover{
    color: #000000;
    background-color: #e9ecf2;
    border: none;
  }
  .ant-dropdown-link{
    font-size: 14px;
    height: 24px;
    padding: 0 7px;
    border-radius: 4px;
    align-content: center;
    text-align: center;
  }
  
  .ellipsis{
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
</style>