可信代码库-AI大模型创建会话\会话列表\会话详情接口对接及前端功能开发

This commit is contained in:
付民康
2025-05-15 15:29:01 +08:00
parent 9af1bc8285
commit 9bebf2fdb8
7 changed files with 969 additions and 235 deletions

View File

@@ -50,7 +50,6 @@ const router = useRouter();
const route = useRoute();
const props = defineProps(['content'])
debugger
const filterTableRef = ref();
const { namespace } = getOrgInfo();
@@ -96,7 +95,6 @@ const fieldTranslation = {
const columns = ref([ ]);
// 处理数据,生成列信息
const processData = () => {
debugger
const uniqueKeys = new Set();
tableData.value.forEach((item) => {
Object.keys(item).forEach((key) => uniqueKeys.add(key));
@@ -104,8 +102,8 @@ const processData = () => {
columns.value = Array.from(uniqueKeys).map((key) => ({
key,
// label: fieldTranslation[key] || key,
label: key,
label: fieldTranslation[key] || key,
// label: key,
width: 120
}));
tableKey.value++;
@@ -114,7 +112,6 @@ const processData = () => {
// 监听数据变化,重新处理数据
watch(() => props.content, (newData) => {
tableData.value = JSON.parse(newData);
debugger
processData();
}, { deep: true,immediate:true });

View File

@@ -0,0 +1,211 @@
<template>
<d-modal v-model="visible" title="批量管理" :style="{ width: '800px' }">
<d-tabs class="jyh-tabs-4" type="wrapped" v-model="selectTab">
<d-tab id="dhls" title="对话历史">
<d-search icon-position="left" style="width: '100%'" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
<div class="mt-3 px-20">
<d-table
class="jyh-table"
:data="filteredTableData"
row-key="id"
@check-change="treeCheckChange"
:pagination="pagination"
:indent="32"
>
<d-column type="checkable" width="40" :checkable="checkable" reserve-check></d-column>
<d-column field="conversationContent" header="对话内容" show-overflow-tooltip></d-column>
<d-column field="agent" header="智能体" show-overflow-tooltip></d-column>
<d-column field="conversationTime" header="发起对话时间" show-overflow-tooltip></d-column>
<d-column width="80" field="operation" header="操作">
<template #default="scope">
<d-icon style="cursor: pointer" @click="handleDelete(scope.row)" name="delete"></d-icon>
</template>
</d-column>
</d-table>
</div>
<div class="mt-20 mb-20 flex justify-end">
<d-pagination
size="md"
:page-size-options="[10, 20, 50]"
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:max-items="5"
:can-change-page-size="true"
:can-view-total="true"
total-item-text="总计"
@page-index-change="getList()"
@page-size-change="getList()"
/>
</div>
</d-tab>
<d-tab id="scdh" title="收藏对话">
<d-search icon-position="left" style="width: '100%'" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
<div class="mt-3 px-20">
<d-table
class="jyh-table"
:data="filteredTableData"
row-key="id"
@check-change="treeCheckChange"
:pagination="pagination"
:indent="32"
>
<d-column type="checkable" width="40" :checkable="checkable" reserve-check></d-column>
<d-column field="conversationContent" header="对话内容" show-overflow-tooltip></d-column>
<d-column field="agent" header="智能体" show-overflow-tooltip></d-column>
<d-column field="conversationTime" header="发起对话时间" show-overflow-tooltip></d-column>
<d-column width="80" field="operation" header="操作">
<template #default="scope">
<d-icon style="cursor: pointer" @click="handleDelete(scope.row)" name="delete"></d-icon>
</template>
</d-column>
</d-table>
</div>
</d-tab>
</d-tabs>
<template #footer>
<div style="text-align: center;margin-bottom: 16px;">
<d-button variant="solid" class="mr-[8px]" @click="handleDeleteSelected">
删除所选
</d-button>
<d-button @click="handleCancel">取消</d-button>
</div>
</template>
</d-modal>
</template>
<script setup>
import { ref, defineExpose, reactive } from 'vue';
const selectTab = ref('dhls');
// 控制弹框显示
const visible = ref(false);
// 搜索文本
const searchText = ref('');
// 表格数据(模拟数据)
const tableData = ref([
{
id: 1,
conversationContent: '这是对话内容1',
agent: '智能体1',
conversationTime: '2024-01-01 10:00:00',
},
{
id: 2,
conversationContent: '这是对话内容2',
agent: '智能体2',
conversationTime: '2024-01-02 11:00:00',
},
]);
// 过滤后的表格数据
const filteredTableData = ref(tableData.value);
// 分页配置
const pagination = ref({
total: tableData.value.length,
current: 1,
pageSize: 10,
});
// 分页器数据
const pager = reactive({
pageIndex: 1,
pageSize: 10,
total: tableData.value.length,
});
// 表格复选框是否可勾选
const checkable = ref(true);
// 复选框选中状态变化时的回调函数
const treeCheckChange = (checkedRowKeys) => {
console.log('选中的行键:', checkedRowKeys);
};
// 搜索按钮点击事件处理函数
const handleSearch = () => {
// 简单的过滤逻辑,根据搜索文本过滤表格数据
const filtered = tableData.value.filter((row) => {
return row.conversationContent.includes(searchText.value);
});
filteredTableData.value = filtered;
pagination.value.total = filtered.length;
pager.total = filtered.length;
pager.pageIndex = 1;
pagination.value.current = 1;
};
// 设置选中行
const setSelectRow = (row) => {
console.log('选中的行:', row);
};
// 删除按钮点击事件处理函数
const handleDelete = (row) => {
// 从表格数据中删除该行
const index = tableData.value.findIndex((r) => r.id === row.id);
if (index > -1) {
tableData.value.splice(index, 1);
filteredTableData.value = tableData.value;
pagination.value.total = filteredTableData.value.length;
pager.total = filteredTableData.value.length;
}
};
// 取消按钮点击事件处理函数
const handleCancel = () => {
visible.value = false;
};
// 确定按钮点击事件处理函数
const handleConfirm = () => {
console.log('确定按钮点击');
};
// 打开模态框
const openModal = () => {
visible.value = true;
};
// 关闭模态框
const handleClose = () => {
visible.value = false;
};
// 删除所选按钮点击事件处理函数
const handleDeleteSelected = () => {
const checkedRowKeys = [];
filteredTableData.value.forEach((row, index) => {
// 这里假设表格有一个属性来标记是否选中比如isChecked
if (row.isChecked) {
checkedRowKeys.push(row.id);
}
});
checkedRowKeys.forEach((id) => {
const index = tableData.value.findIndex((r) => r.id === id);
if (index > -1) {
tableData.value.splice(index, 1);
}
});
filteredTableData.value = tableData.value;
pagination.value.total = filteredTableData.value.length;
pager.total = filteredTableData.value.length;
console.log('删除所选按钮点击');
};
// 暴露方法,供父组件调用
defineExpose({
openModal,
});
</script>
<style scoped>
.search-container {
display: flex;
align-items: center;
margin-bottom: 16px;
}
</style>

View File

@@ -0,0 +1,412 @@
<template>
<Card class="ViewHistoryAside">
<d-tabs class="jyh-tabs-4" type="wrapped" v-model="selectTab">
<d-tab id="dhls" title="对话历史">
<d-search icon-position="left" style="width: 100%" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
<!-- 可滚动内容区域 -->
<div class="scrollable-content">
<d-collapse class="jyh-collapse" v-model="collapseValue">
<d-collapse-item name="today">
<template #title>
<div class="jyh-collapse-title">
<d-icon style="margin-right: 4px" name="icon-delay"></d-icon>今天
</div>
</template>
<div>
<!-- 循环生成卡片列表 -->
<div v-if="dhlsList.length>0">
<div
v-for="(item, index) in dhlsList"
:key="index"
:class="['mb-3 jyh-collapse-card', { 'selected-card': props.CONV_ID === item.conversationId }]"
@click="handleSelect(item)"
@mouseenter="hoverIndex = index"
@mouseleave="hoverIndex = null"
>
<!-- 卡片标题 -->
<div class="card-header">
<h4>{{ item.title }}</h4>
<!-- 悬停操作按钮 -->
<div class="card-actions" v-show="hoverIndex === index">
<d-tooltip content="编辑">
<d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleEdit(item)" name="icon-edit-3"></d-icon>
</d-tooltip>
<d-tooltip content="分享">
<d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleShare(item)" name="icon-redo-new"></d-icon>
</d-tooltip>
<d-tooltip content="更多">
<d-icon style="font-size: 14px;" @click.stop="handleMore(item)" name="icon-more-operate"></d-icon>
</d-tooltip>
</div>
</div>
<!-- 卡片内容 -->
<div class="card-content">
<div class="content-left">
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
<span>{{ item.text || '可信代码库AI' }}</span>
</div>
<div class="content-right">
<span class="time-text">{{ item.createTime||'--' }}</span>
</div>
</div>
</div>
</div>
<NoData v-else :small="false"></NoData>
</div>
</d-collapse-item>
<!-- <d-collapse-item name="yestoday">-->
<!-- <template #title>-->
<!-- <div class="jyh-collapse-title">-->
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天-->
<!-- </div>-->
<!-- </template>-->
<!-- <div>-->
<!-- <div-->
<!-- v-for="(item, index) in cardList"-->
<!-- :key="index"-->
<!-- class="mb-3 jyh-collapse-card"-->
<!-- >-->
<!-- &lt;!&ndash; 卡片标题 &ndash;&gt;-->
<!-- <div class="card-header">-->
<!-- <h4>{{ item.title }}</h4>-->
<!-- </div>-->
<!-- &lt;!&ndash; 卡片内容 &ndash;&gt;-->
<!-- <div class="card-content">-->
<!-- <div class="content-left">-->
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
<!-- <span>{{ item.text }}</span>-->
<!-- </div>-->
<!-- <div class="content-right">-->
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </d-collapse-item>-->
</d-collapse>
</div>
<!-- 固定在底部的控制栏 -->
<div class="bottom-control-bar">
<div class="control-left">
历史对话保存条数
<d-select
v-model="historyLimit"
style="width: 60px"
size="sm"
class="jyh-select"
>
<d-option value="10">10</d-option>
<d-option value="20">20</d-option>
<d-option value="30">30</d-option>
<d-option value="0">0</d-option>
</d-select>
</div>
<div class="control-right">
<d-button class="jyh-button2" variant="solid" @click="openBatchManageModal">
<template #icon>
<d-icon name="icon-property-setting"></d-icon>
</template>
批量管理
</d-button>
<BatchManageModal ref="BatchManageModalRef"/>
</div>
</div>
</d-tab>
<d-tab id="scdh" title="收藏对话">
<d-search icon-position="left" style="width: 100%" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
<!-- 可滚动内容区域 -->
<div class="scrollable-content">
<!-- <d-collapse class="jyh-collapse" v-model="collapseValue">-->
<!-- <d-collapse-item name="today">-->
<!-- <template #title>-->
<!-- <div class="jyh-collapse-title">-->
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>今天-->
<!-- </div>-->
<!-- </template>-->
<!-- <div>-->
<!-- &lt;!&ndash; 循环生成卡片列表 &ndash;&gt;-->
<!-- <div v-if="cardList.length>0">-->
<!-- <div-->
<!-- v-for="(item, index) in cardList"-->
<!-- :key="index"-->
<!-- :class="['mb-3 jyh-collapse-card', { 'selected-card': selectedIndex === item.id }]"-->
<!-- @click="selectCard(item)"-->
<!-- @mouseenter="hoverIndex = index"-->
<!-- @mouseleave="hoverIndex = null"-->
<!-- >-->
<!-- &lt;!&ndash; 卡片标题 &ndash;&gt;-->
<!-- <div class="card-header">-->
<!-- <h4>{{ item.title }}</h4>-->
<!-- &lt;!&ndash; 悬停操作按钮 &ndash;&gt;-->
<!-- <div class="card-actions" v-show="hoverIndex === index">-->
<!-- <d-tooltip content="编辑">-->
<!-- <d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleEdit(item)" name="icon-edit-3"></d-icon>-->
<!-- </d-tooltip>-->
<!-- <d-tooltip content="分享">-->
<!-- <d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleShare(item)" name="icon-redo-new"></d-icon>-->
<!-- </d-tooltip>-->
<!-- <d-tooltip content="更多">-->
<!-- <d-icon style="font-size: 14px;" @click.stop="handleMore(item)" name="icon-more-operate"></d-icon>-->
<!-- </d-tooltip>-->
<!-- </div>-->
<!-- </div>-->
<!-- &lt;!&ndash; 卡片内容 &ndash;&gt;-->
<!-- <div class="card-content">-->
<!-- <div class="content-left">-->
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
<!-- <span>{{ item.text }}</span>-->
<!-- </div>-->
<!-- <div class="content-right">-->
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <NoData v-else :small="false"></NoData>-->
<!-- </div>-->
<!-- </d-collapse-item>-->
<!-- <d-collapse-item name="yestoday">-->
<!-- <template #title>-->
<!-- <div class="jyh-collapse-title">-->
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天-->
<!-- </div>-->
<!-- </template>-->
<!-- <div>-->
<!-- <div-->
<!-- v-for="(item, index) in cardList"-->
<!-- :key="index"-->
<!-- class="mb-3 jyh-collapse-card"-->
<!-- >-->
<!-- &lt;!&ndash; 卡片标题 &ndash;&gt;-->
<!-- <div class="card-header">-->
<!-- <h4>{{ item.title }}</h4>-->
<!-- </div>-->
<!-- &lt;!&ndash; 卡片内容 &ndash;&gt;-->
<!-- <div class="card-content">-->
<!-- <div class="content-left">-->
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
<!-- <span>{{ item.text }}</span>-->
<!-- </div>-->
<!-- <div class="content-right">-->
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </d-collapse-item>-->
<!-- </d-collapse>-->
</div>
<!-- 固定在底部的控制栏 -->
<div class="bottom-control-bar">
<div class="control-left">
历史对话保存条数
<d-select
v-model="historyLimit"
style="width: 60px"
size="sm"
class="jyh-select"
>
<d-option value="10">10</d-option>
<d-option value="20">20</d-option>
<d-option value="30">30</d-option>
<d-option value="0">0</d-option>
</d-select>
</div>
<div class="control-right">
<d-button class="jyh-button2" variant="solid" @click="openBatchManageModal">
<template #icon>
<d-icon name="icon-property-setting"></d-icon>
</template>
批量管理
</d-button>
<BatchManageModal ref="BatchManageModalRef"/>
</div>
</div>
</d-tab>
</d-tabs>
</Card>
</template>
<script setup>
import { onMounted, ref, defineEmits,defineExpose } from 'vue';
import BatchManageModal from './BatchManageModal.vue'
import axios from 'axios';
import { Message } from 'vue-devui/message';
import { useTimeFormat } from '@/utils/hooks/useTimeFormat';
import NoData from '@/components/NoData/NoData.vue';
// 定义父组件通信的事件
const emit = defineEmits(['select-conv']);
const props = defineProps(['username','CONV_ID'])
// 定义每个卡片的展开状态
const selectTab = ref('dhls');
const searchText = ref(''); // 搜索关键词
const collapseValue = ref(['today']);
const historyLimit = ref('30');
const hoverIndex = ref(null);
const BatchManageModalRef = ref(null);
const { formatTime } = useTimeFormat();
const handleSelect = (item) => {
// 触发父组件事件,传递选中的 convId
emit('select-conv', item.conversationId);
};
// 打开弹框的方法
const openBatchManageModal = () => {
if (BatchManageModalRef.value) {
BatchManageModalRef.value.openModal();
}
};
const handleEdit = (item) => {
console.log('编辑:', item);
// 这里添加编辑逻辑
};
const handleShare = (item) => {
console.log('分享:', item);
// 这里添加分享逻辑
};
const handleMore = (item) => {
console.log('分享:', item);
// 这里添加分享逻辑
};
// 模拟数据
const cardList = ref([
{
title: '项目进度报告',
icon: 'icon-project',
text: '已完成需求评审',
time: new Date(),
id: 1,
},
{
title: '系统维护通知',
icon: 'icon-maintenance',
text: '系统将于今晚24:00进行维护',
time: new Date(Date.now() + 3600000),
id: 2,
},
{
title: '会议提醒',
icon: 'icon-meeting',
text: '下午3点项目组会议',
time: new Date(Date.now() + 21600000),
id: 3,
}
]);
const dhlsList = ref([]);
const VITE_AI_API_HOST = import.meta.env.VITE_AI_API_HOST;
const getQuestionHistory = async () => {
if(props.username) {
const {data} = await axios.get(VITE_AI_API_HOST + '/api/conversationList?userId='+props.username);
if(data.conversationList) {
debugger
dhlsList.value = data.conversationList
} else {
// Message.error(data.error||'接口异常!')
}
} else {
Message.warning('请先登录!')
}
};
onMounted(() => {
getQuestionHistory()
});
defineExpose({
getQuestionHistory // 直接暴露方法
});
</script>
<style lang="scss" scoped>
.ViewHistoryAside {
width: 18vw;
position: fixed;
top: 64px;
left: 20px;
height: 85vh;
.jyh-tabs-4 {
height: 100% !important;
display: flex;
flex-direction: column;
:deep(.devui-tabs__nav) {
border-bottom: 0 !important;
}
:deep(.devui-tabs__nav--wrapped)>li.active a {
color: black !important;
}
:deep(.devui-tab__content) {
height: 100% !important;
}
:deep(.devui-tab__content > div) {
height: 100% !important;
}
}
.jyh-collapse {
height: 100%; // 添加这一行设置高度为100%
.devui-collapse__item-title {
padding: 0 !important;
}
.jyh-collapse-title {
display: flex;
align-items: center;
}
}
.scrollable-content {
flex: 1;
overflow-y: auto;
padding-bottom: 60px; /* 为底部控制栏留出空间 */
margin-bottom: -16px; /* 抵消Card的padding */
/* 细滚动条样式 */
scrollbar-width: thin;
scrollbar-color: #ddd transparent;
height: 100%; // 添加这一行设置高度为100%
}
.scrollable-content::-webkit-scrollbar {
width: 4px;
}
.scrollable-content::-webkit-scrollbar-thumb {
background-color: #ddd;
border-radius: 2px;
}
.scrollable-content::-webkit-scrollbar-track {
background: transparent;
}
.bottom-control-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background: white;
border-top: 1px solid #f0f0f0;
z-index: 1;
.control-left, .control-right {
display: flex;
align-items: center;
}
}
}
</style>