可信代码库-AI大模型创建会话\会话列表\会话详情接口对接及前端功能开发
This commit is contained in:
@@ -38,4 +38,4 @@ VITE_COPILOT_HOST = 'https://test.gitcode.net/child/aichat-app/'
|
|||||||
VITE_BASE_URL=/
|
VITE_BASE_URL=/
|
||||||
|
|
||||||
# AI大模型接口地址
|
# AI大模型接口地址
|
||||||
VITE_AI_API_HOST = 'http://222.20.126.208:8089'
|
VITE_AI_API_HOST = 'http://222.20.126.208:8087'
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<!-- 循环生成卡片列表 -->
|
<!-- 循环生成卡片列表 -->
|
||||||
<div v-if="cardList.length>0">
|
<div v-if="dhlsList.length>0">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in cardList"
|
v-for="(item, index) in dhlsList"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="['mb-3 jyh-collapse-card', { 'selected-card': selectedIndex === item.id }]"
|
:class="['mb-3 jyh-collapse-card', { 'selected-card': selectedIndex === item.id }]"
|
||||||
@click="selectCard(item)"
|
@click="selectCard(item)"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
>
|
>
|
||||||
<!-- 卡片标题 -->
|
<!-- 卡片标题 -->
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h4>{{ item.title }}</h4>
|
<h4>{{ item.question }}</h4>
|
||||||
<!-- 悬停操作按钮 -->
|
<!-- 悬停操作按钮 -->
|
||||||
<div class="card-actions" v-show="hoverIndex === index">
|
<div class="card-actions" v-show="hoverIndex === index">
|
||||||
<d-tooltip content="编辑">
|
<d-tooltip content="编辑">
|
||||||
@@ -43,10 +43,10 @@
|
|||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="content-left">
|
<div class="content-left">
|
||||||
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text || '可信代码库AI' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-right">
|
<div class="content-right">
|
||||||
<span class="time-text">{{ formatTime(item.time) }}</span>
|
<span class="time-text">时间:{{ formatTime(item.time||'') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,35 +54,35 @@
|
|||||||
<NoData v-else :small="false"></NoData>
|
<NoData v-else :small="false"></NoData>
|
||||||
</div>
|
</div>
|
||||||
</d-collapse-item>
|
</d-collapse-item>
|
||||||
<d-collapse-item name="yestoday">
|
<!-- <d-collapse-item name="yestoday">-->
|
||||||
<template #title>
|
<!-- <template #title>-->
|
||||||
<div class="jyh-collapse-title">
|
<!-- <div class="jyh-collapse-title">-->
|
||||||
<d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天
|
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<div
|
<!-- <div-->
|
||||||
v-for="(item, index) in cardList"
|
<!-- v-for="(item, index) in cardList"-->
|
||||||
:key="index"
|
<!-- :key="index"-->
|
||||||
class="mb-3 jyh-collapse-card"
|
<!-- class="mb-3 jyh-collapse-card"-->
|
||||||
>
|
<!-- >-->
|
||||||
<!-- 卡片标题 -->
|
<!-- <!– 卡片标题 –>-->
|
||||||
<div class="card-header">
|
<!-- <div class="card-header">-->
|
||||||
<h4>{{ item.title }}</h4>
|
<!-- <h4>{{ item.title }}</h4>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<!-- 卡片内容 -->
|
<!-- <!– 卡片内容 –>-->
|
||||||
<div class="card-content">
|
<!-- <div class="card-content">-->
|
||||||
<div class="content-left">
|
<!-- <div class="content-left">-->
|
||||||
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
|
||||||
<span>{{ item.text }}</span>
|
<!-- <span>{{ item.text }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="content-right">
|
<!-- <div class="content-right">-->
|
||||||
<span class="time-text">{{ formatTime(item.time) }}</span>
|
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</d-collapse-item>
|
<!-- </d-collapse-item>-->
|
||||||
</d-collapse>
|
</d-collapse>
|
||||||
</div>
|
</div>
|
||||||
<!-- 固定在底部的控制栏 -->
|
<!-- 固定在底部的控制栏 -->
|
||||||
@@ -116,85 +116,85 @@
|
|||||||
<d-search icon-position="left" style="width: 100%" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
|
<d-search icon-position="left" style="width: 100%" placeholder="请输入搜索软件名称" v-model="searchText" @change="handleSearch"></d-search>
|
||||||
<!-- 可滚动内容区域 -->
|
<!-- 可滚动内容区域 -->
|
||||||
<div class="scrollable-content">
|
<div class="scrollable-content">
|
||||||
<d-collapse class="jyh-collapse" v-model="collapseValue">
|
<!-- <d-collapse class="jyh-collapse" v-model="collapseValue">-->
|
||||||
<d-collapse-item name="today">
|
<!-- <d-collapse-item name="today">-->
|
||||||
<template #title>
|
<!-- <template #title>-->
|
||||||
<div class="jyh-collapse-title">
|
<!-- <div class="jyh-collapse-title">-->
|
||||||
<d-icon style="margin-right: 4px" name="icon-delay"></d-icon>今天
|
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>今天-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<!-- 循环生成卡片列表 -->
|
<!-- <!– 循环生成卡片列表 –>-->
|
||||||
<div v-if="cardList.length>0">
|
<!-- <div v-if="cardList.length>0">-->
|
||||||
<div
|
<!-- <div-->
|
||||||
v-for="(item, index) in cardList"
|
<!-- v-for="(item, index) in cardList"-->
|
||||||
:key="index"
|
<!-- :key="index"-->
|
||||||
:class="['mb-3 jyh-collapse-card', { 'selected-card': selectedIndex === item.id }]"
|
<!-- :class="['mb-3 jyh-collapse-card', { 'selected-card': selectedIndex === item.id }]"-->
|
||||||
@click="selectCard(item)"
|
<!-- @click="selectCard(item)"-->
|
||||||
@mouseenter="hoverIndex = index"
|
<!-- @mouseenter="hoverIndex = index"-->
|
||||||
@mouseleave="hoverIndex = null"
|
<!-- @mouseleave="hoverIndex = null"-->
|
||||||
>
|
<!-- >-->
|
||||||
<!-- 卡片标题 -->
|
<!-- <!– 卡片标题 –>-->
|
||||||
<div class="card-header">
|
<!-- <div class="card-header">-->
|
||||||
<h4>{{ item.title }}</h4>
|
<!-- <h4>{{ item.title }}</h4>-->
|
||||||
<!-- 悬停操作按钮 -->
|
<!-- <!– 悬停操作按钮 –>-->
|
||||||
<div class="card-actions" v-show="hoverIndex === index">
|
<!-- <div class="card-actions" v-show="hoverIndex === index">-->
|
||||||
<d-tooltip content="编辑">
|
<!-- <d-tooltip content="编辑">-->
|
||||||
<d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleEdit(item)" name="icon-edit-3"></d-icon>
|
<!-- <d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleEdit(item)" name="icon-edit-3"></d-icon>-->
|
||||||
</d-tooltip>
|
<!-- </d-tooltip>-->
|
||||||
<d-tooltip content="分享">
|
<!-- <d-tooltip content="分享">-->
|
||||||
<d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleShare(item)" name="icon-redo-new"></d-icon>
|
<!-- <d-icon style="font-size: 14px;margin-right: 2px" @click.stop="handleShare(item)" name="icon-redo-new"></d-icon>-->
|
||||||
</d-tooltip>
|
<!-- </d-tooltip>-->
|
||||||
<d-tooltip content="更多">
|
<!-- <d-tooltip content="更多">-->
|
||||||
<d-icon style="font-size: 14px;" @click.stop="handleMore(item)" name="icon-more-operate"></d-icon>
|
<!-- <d-icon style="font-size: 14px;" @click.stop="handleMore(item)" name="icon-more-operate"></d-icon>-->
|
||||||
</d-tooltip>
|
<!-- </d-tooltip>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<!-- 卡片内容 -->
|
<!-- <!– 卡片内容 –>-->
|
||||||
<div class="card-content">
|
<!-- <div class="card-content">-->
|
||||||
<div class="content-left">
|
<!-- <div class="content-left">-->
|
||||||
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
|
||||||
<span>{{ item.text }}</span>
|
<!-- <span>{{ item.text }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="content-right">
|
<!-- <div class="content-right">-->
|
||||||
<span class="time-text">{{ formatTime(item.time) }}</span>
|
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<NoData v-else :small="false"></NoData>
|
<!-- <NoData v-else :small="false"></NoData>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</d-collapse-item>
|
<!-- </d-collapse-item>-->
|
||||||
<d-collapse-item name="yestoday">
|
<!-- <d-collapse-item name="yestoday">-->
|
||||||
<template #title>
|
<!-- <template #title>-->
|
||||||
<div class="jyh-collapse-title">
|
<!-- <div class="jyh-collapse-title">-->
|
||||||
<d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天
|
<!-- <d-icon style="margin-right: 4px" name="icon-delay"></d-icon>昨天-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<div
|
<!-- <div-->
|
||||||
v-for="(item, index) in cardList"
|
<!-- v-for="(item, index) in cardList"-->
|
||||||
:key="index"
|
<!-- :key="index"-->
|
||||||
class="mb-3 jyh-collapse-card"
|
<!-- class="mb-3 jyh-collapse-card"-->
|
||||||
>
|
<!-- >-->
|
||||||
<!-- 卡片标题 -->
|
<!-- <!– 卡片标题 –>-->
|
||||||
<div class="card-header">
|
<!-- <div class="card-header">-->
|
||||||
<h4>{{ item.title }}</h4>
|
<!-- <h4>{{ item.title }}</h4>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<!-- 卡片内容 -->
|
<!-- <!– 卡片内容 –>-->
|
||||||
<div class="card-content">
|
<!-- <div class="card-content">-->
|
||||||
<div class="content-left">
|
<!-- <div class="content-left">-->
|
||||||
<img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
<!-- <img width="16" style="margin-right: 4px" src="@/assets/imgs/jyh/ai/aiLogo2.png" />-->
|
||||||
<span>{{ item.text }}</span>
|
<!-- <span>{{ item.text }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="content-right">
|
<!-- <div class="content-right">-->
|
||||||
<span class="time-text">{{ formatTime(item.time) }}</span>
|
<!-- <span class="time-text">{{ formatTime(item.time) }}</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</d-collapse-item>
|
<!-- </d-collapse-item>-->
|
||||||
</d-collapse>
|
<!-- </d-collapse>-->
|
||||||
</div>
|
</div>
|
||||||
<!-- 固定在底部的控制栏 -->
|
<!-- 固定在底部的控制栏 -->
|
||||||
<div class="bottom-control-bar">
|
<div class="bottom-control-bar">
|
||||||
@@ -228,19 +228,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import BatchManageModal from './BatchManageModal.vue'
|
import BatchManageModal from './BatchManageModal.vue'
|
||||||
|
import axios from 'axios';
|
||||||
|
import { Message } from 'vue-devui/message';
|
||||||
|
import { useTimeFormat } from '@/utils/hooks/useTimeFormat';
|
||||||
|
|
||||||
// 定义每个卡片的展开状态
|
// 定义每个卡片的展开状态
|
||||||
const selectTab = ref('dhls');
|
const selectTab = ref('dhls');
|
||||||
const searchText = ref(''); // 搜索关键词
|
const searchText = ref(''); // 搜索关键词
|
||||||
const collapseValue = ref([]);
|
const collapseValue = ref(['today']);
|
||||||
const historyLimit = ref('30');
|
const historyLimit = ref('30');
|
||||||
// 当前选中的卡片索引
|
// 当前选中的卡片索引
|
||||||
const selectedIndex = ref(null);
|
const selectedIndex = ref(null);
|
||||||
const hoverIndex = ref(null);
|
const hoverIndex = ref(null);
|
||||||
const BatchManageModalRef = ref(null);
|
const BatchManageModalRef = ref(null);
|
||||||
|
|
||||||
|
const { formatTime } = useTimeFormat();
|
||||||
|
|
||||||
// 打开弹框的方法
|
// 打开弹框的方法
|
||||||
const openBatchManageModal = () => {
|
const openBatchManageModal = () => {
|
||||||
if (BatchManageModalRef.value) {
|
if (BatchManageModalRef.value) {
|
||||||
@@ -286,6 +291,7 @@ const cardList = ref([
|
|||||||
id: 3,
|
id: 3,
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
const dhlsList = ref([]);
|
||||||
|
|
||||||
// 选择卡片
|
// 选择卡片
|
||||||
const selectCard = (item) => {
|
const selectCard = (item) => {
|
||||||
@@ -295,11 +301,22 @@ const selectCard = (item) => {
|
|||||||
// console.log('选中卡片:', cardList.value[index]);
|
// console.log('选中卡片:', cardList.value[index]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const VITE_AI_API_HOST = import.meta.env.VITE_AI_API_HOST;
|
||||||
// 格式化时间
|
const getQuestionHistory = async (content) => {
|
||||||
const formatTime = (date) => {
|
/*TODO:缺少用户名入参*/
|
||||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
const {data} = await axios.get(VITE_AI_API_HOST + '/api/conversationList?userId=?');
|
||||||
|
if(data.questions) {
|
||||||
|
debugger
|
||||||
|
dhlsList.value = data.questions
|
||||||
|
} else {
|
||||||
|
Message.warning('接口异常!')
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getQuestionHistory()
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -61,18 +61,7 @@
|
|||||||
</d-layout>
|
</d-layout>
|
||||||
|
|
||||||
<!-- 浮动工具栏(移动端不显示) -->
|
<!-- 浮动工具栏(移动端不显示) -->
|
||||||
<!-- <ToolsFloat v-if="showToolsFloat" />-->
|
<!--<ToolsFloat v-if="showToolsFloat" />-->
|
||||||
<!-- 在 d-layout 结束前添加返回按钮 -->
|
|
||||||
<div class="back-in-btn">
|
|
||||||
<div class="back-in-time-btn" @click="toggleHistory" :class="{ 'active': isHistoryVisible }">
|
|
||||||
<i class="icon icon-history" title="查看历史"></i>
|
|
||||||
</div>
|
|
||||||
<div class="back-in-time-btn" @click="handleBackInTime">
|
|
||||||
<i class="icon icon-operation-log" title="查看文档"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ViewHistoryAside v-show="isHistoryVisible"/>
|
|
||||||
</d-layout>
|
</d-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -82,7 +71,6 @@ import { computed, ref, watch, watchEffect, onMounted, onUnmounted } from 'vue';
|
|||||||
import AIHeader from '@/components/Header/AIHeader.vue';
|
import AIHeader from '@/components/Header/AIHeader.vue';
|
||||||
import Footer from '@/components/Footer/index.vue';
|
import Footer from '@/components/Footer/index.vue';
|
||||||
import Aside from './aside.vue';
|
import Aside from './aside.vue';
|
||||||
import ViewHistoryAside from './ViewHistoryAside/ViewHistoryAside.vue';
|
|
||||||
import { useGlobalInfoStore } from '@/stores/Global';
|
import { useGlobalInfoStore } from '@/stores/Global';
|
||||||
|
|
||||||
import ToolsFloat from '@/components/ToolsFloat/index.vue';
|
import ToolsFloat from '@/components/ToolsFloat/index.vue';
|
||||||
@@ -90,7 +78,6 @@ import { useStorage, useElementSize } from '@vueuse/core';
|
|||||||
import { usePageResize } from '@/utils/hooks/usePageResize';
|
import { usePageResize } from '@/utils/hooks/usePageResize';
|
||||||
import microApp from '@micro-zoe/micro-app';
|
import microApp from '@micro-zoe/micro-app';
|
||||||
|
|
||||||
|
|
||||||
defineOptions({ name: 'AILayout' });
|
defineOptions({ name: 'AILayout' });
|
||||||
defineProps<{ customAside?: boolean; }>();
|
defineProps<{ customAside?: boolean; }>();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -104,9 +91,6 @@ const refHeader: any = ref(null);
|
|||||||
const footerSize = useElementSize(refFooter);
|
const footerSize = useElementSize(refFooter);
|
||||||
const isHome = computed(() => route.name === 'home');
|
const isHome = computed(() => route.name === 'home');
|
||||||
|
|
||||||
// 控制 ViewHistoryAside 组件的显示状态
|
|
||||||
const isHistoryVisible = ref(false);
|
|
||||||
|
|
||||||
// aside 设置可见性 header有两层,有顶栏信息,两层sidebar 都不可见
|
// aside 设置可见性 header有两层,有顶栏信息,两层sidebar 都不可见
|
||||||
const asideSetShow = computed(() => {
|
const asideSetShow = computed(() => {
|
||||||
if (route.meta.asideMenu === 'drawer') return false;
|
if (route.meta.asideMenu === 'drawer') return false;
|
||||||
@@ -162,11 +146,6 @@ const handleClickMenu = () => {
|
|||||||
asideDefaultWidth.value = asideDefaultWidth.value >= 240 ? 0 : 240;
|
asideDefaultWidth.value = asideDefaultWidth.value >= 240 ? 0 : 240;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 切换 ViewHistoryAside 组件的显示与隐藏
|
|
||||||
const toggleHistory = () => {
|
|
||||||
isHistoryVisible.value =!isHistoryVisible.value;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -210,49 +189,4 @@ const toggleHistory = () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-in-btn {
|
|
||||||
position: fixed;
|
|
||||||
left: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
|
|
||||||
.active {
|
|
||||||
background-color: #f0f0f0; /* 灰色背景 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.active .icon {
|
|
||||||
transform: translateY(-4px); /* 图标上移4px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-in-time-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 8px;
|
|
||||||
background-color: var(--el-color-primary);
|
|
||||||
//color: white;
|
|
||||||
border-radius: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
z-index: 999;
|
|
||||||
transition: all 0.3s;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-in-time-btn:hover {
|
|
||||||
background-color: var(--el-color-primary-light-3);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式调整 - 移动端隐藏或调整位置 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.back-in-time-btn {
|
|
||||||
left: 10px;
|
|
||||||
bottom: 10px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ const router = useRouter();
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const props = defineProps(['content'])
|
const props = defineProps(['content'])
|
||||||
debugger
|
|
||||||
|
|
||||||
const filterTableRef = ref();
|
const filterTableRef = ref();
|
||||||
const { namespace } = getOrgInfo();
|
const { namespace } = getOrgInfo();
|
||||||
@@ -96,7 +95,6 @@ const fieldTranslation = {
|
|||||||
const columns = ref([ ]);
|
const columns = ref([ ]);
|
||||||
// 处理数据,生成列信息
|
// 处理数据,生成列信息
|
||||||
const processData = () => {
|
const processData = () => {
|
||||||
debugger
|
|
||||||
const uniqueKeys = new Set();
|
const uniqueKeys = new Set();
|
||||||
tableData.value.forEach((item) => {
|
tableData.value.forEach((item) => {
|
||||||
Object.keys(item).forEach((key) => uniqueKeys.add(key));
|
Object.keys(item).forEach((key) => uniqueKeys.add(key));
|
||||||
@@ -104,8 +102,8 @@ const processData = () => {
|
|||||||
|
|
||||||
columns.value = Array.from(uniqueKeys).map((key) => ({
|
columns.value = Array.from(uniqueKeys).map((key) => ({
|
||||||
key,
|
key,
|
||||||
// label: fieldTranslation[key] || key,
|
label: fieldTranslation[key] || key,
|
||||||
label: key,
|
// label: key,
|
||||||
width: 120
|
width: 120
|
||||||
}));
|
}));
|
||||||
tableKey.value++;
|
tableKey.value++;
|
||||||
@@ -114,7 +112,6 @@ const processData = () => {
|
|||||||
// 监听数据变化,重新处理数据
|
// 监听数据变化,重新处理数据
|
||||||
watch(() => props.content, (newData) => {
|
watch(() => props.content, (newData) => {
|
||||||
tableData.value = JSON.parse(newData);
|
tableData.value = JSON.parse(newData);
|
||||||
debugger
|
|
||||||
processData();
|
processData();
|
||||||
}, { deep: true,immediate:true });
|
}, { deep: true,immediate:true });
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <!– 卡片标题 –>-->
|
||||||
|
<!-- <div class="card-header">-->
|
||||||
|
<!-- <h4>{{ item.title }}</h4>-->
|
||||||
|
<!-- </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 }}</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>-->
|
||||||
|
<!-- <!– 循环生成卡片列表 –>-->
|
||||||
|
<!-- <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"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <!– 卡片标题 –>-->
|
||||||
|
<!-- <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 }}</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"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <!– 卡片标题 –>-->
|
||||||
|
<!-- <div class="card-header">-->
|
||||||
|
<!-- <h4>{{ item.title }}</h4>-->
|
||||||
|
<!-- </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 }}</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>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="home-content">
|
<div class="home-content">
|
||||||
<div v-if="startChat" ref="conversationRef" class="conversation-area">
|
<div v-if="startChat" ref="conversationRef" class="conversation-area">
|
||||||
<template v-for="(msg, idx) in messages" :key="idx">
|
<template v-for="(msg, idx) in messages" :key="idx">
|
||||||
<McBubble v-if="msg.from === 'user'" :content="msg.content" :align="'right'" ></McBubble>
|
<McBubble v-if="msg.role === 'user'" :content="msg.content" :align="'right'" ></McBubble>
|
||||||
<McBubble v-else :loading="msg.loading ?? false" >
|
<McBubble v-else :loading="msg.loading ?? false" >
|
||||||
<div class="think-toggle-btn" @click="toggleThink(idx)">
|
<div class="think-toggle-btn" @click="toggleThink(idx)">
|
||||||
<div class="flex align-middle">
|
<div class="flex align-middle">
|
||||||
@@ -132,6 +132,16 @@
|
|||||||
<p>内容由AI生成,无法确保准确性和完整性,仅供参考:使用条款 隐私声明</p>
|
<p>内容由AI生成,无法确保准确性和完整性,仅供参考:使用条款 隐私声明</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="back-in-btn">
|
||||||
|
<div class="back-in-time-btn" @click="toggleHistory" :class="{ 'active': isHistoryVisible }">
|
||||||
|
<i class="icon icon-history" title="查看历史"></i>
|
||||||
|
</div>
|
||||||
|
<div class="back-in-time-btn" @click="handleBackInTime">
|
||||||
|
<i class="icon icon-operation-log" title="查看文档"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ViewHistoryAside ref="viewHistoryRef" :CONV_ID="CONV_ID" :username="username" v-show="isHistoryVisible" @select-conv="handleSelectConv"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -145,11 +155,14 @@ import WarningList from './components/WarningList.vue';
|
|||||||
import OssDetail from './components/OssDetail.vue';
|
import OssDetail from './components/OssDetail.vue';
|
||||||
import Other from './components/Other.vue';
|
import Other from './components/Other.vue';
|
||||||
import AIList from './components/AIList.vue';
|
import AIList from './components/AIList.vue';
|
||||||
|
import ViewHistoryAside from './components/ViewHistoryAside/ViewHistoryAside.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useDiscussGetUserInfo } from '@/api/discussion/hook';
|
import { useDiscussGetUserInfo } from '@/api/discussion/hook';
|
||||||
|
import { Message } from 'vue-devui/message';
|
||||||
|
|
||||||
// 获取当前用户信息 & 是否登录
|
// 获取当前用户信息 & 是否登录
|
||||||
const { isLogin = false, userInfo = {}} = useDiscussGetUserInfo();
|
const { isLogin = false, userInfo = {}} = useDiscussGetUserInfo();
|
||||||
|
const {username=''} = userInfo
|
||||||
|
|
||||||
const inputValue = ref('');
|
const inputValue = ref('');
|
||||||
const startChat = ref(false);
|
const startChat = ref(false);
|
||||||
@@ -164,6 +177,7 @@ const agentList = ref([
|
|||||||
{ label: 'InsCode', value: 'inscode' },
|
{ label: 'InsCode', value: 'inscode' },
|
||||||
]);
|
]);
|
||||||
const selectedAgent = ref(agentList.value[0]);
|
const selectedAgent = ref(agentList.value[0]);
|
||||||
|
|
||||||
const aiModelAvatar = {
|
const aiModelAvatar = {
|
||||||
imgSrc: 'https://matechat.gitcode.com/logo.svg',
|
imgSrc: 'https://matechat.gitcode.com/logo.svg',
|
||||||
width: 32,
|
width: 32,
|
||||||
@@ -182,13 +196,22 @@ const inputFootIcons = [
|
|||||||
|
|
||||||
const messages = ref([]);
|
const messages = ref([]);
|
||||||
|
|
||||||
|
// 控制 ViewHistoryAside 组件的显示状态
|
||||||
|
const isHistoryVisible = ref(false);
|
||||||
|
|
||||||
|
|
||||||
|
// 切换 ViewHistoryAside 组件的显示与隐藏
|
||||||
|
const toggleHistory = () => {
|
||||||
|
isHistoryVisible.value =!isHistoryVisible.value;
|
||||||
|
};
|
||||||
|
|
||||||
const onInputIconClick = (e) => {
|
const onInputIconClick = (e) => {
|
||||||
if (e.icon === 'icon-at') {
|
if (e.icon === 'icon-at') {
|
||||||
inputValue.value += `@${selectedAgent.value.label}`;
|
inputValue.value += `@${selectedAgent.value.label}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = (e, answer = undefined) => {
|
const onSubmit = async (e, answer = undefined) => {
|
||||||
if(e === '') {
|
if(e === '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -197,70 +220,163 @@ const onSubmit = (e, answer = undefined) => {
|
|||||||
startChat.value = true;
|
startChat.value = true;
|
||||||
}
|
}
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
from: 'user',
|
role: 'user',
|
||||||
content: e,
|
content: e,
|
||||||
avatarPosition: 'side-right',
|
avatarPosition: 'side-right',
|
||||||
avatarConfig: { ...customerAvatar },
|
avatarConfig: { ...customerAvatar },
|
||||||
});
|
});
|
||||||
|
// getAIAnswer(answer ?? e);
|
||||||
|
// 判断是否有会话id
|
||||||
|
if(!CONV_ID.value) {
|
||||||
|
// 调用创建会话接口
|
||||||
|
await createConversation()
|
||||||
|
}
|
||||||
|
await getAIAnswer(e,1);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
conversationRef.value?.scrollTo({
|
conversationRef.value?.scrollTo({
|
||||||
top: conversationRef.value.scrollHeight,
|
top: conversationRef.value.scrollHeight,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// getAIAnswer(answer ?? e);
|
|
||||||
getAIAnswer(e,1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const VITE_AI_API_HOST = (import.meta as any).env.VITE_AI_API_HOST;
|
const VITE_AI_API_HOST = (import.meta as any).env.VITE_AI_API_HOST;
|
||||||
|
|
||||||
|
// AI对话接口对接
|
||||||
const getAIAnswer = async (content) => {
|
const getAIAnswer = async (content) => {
|
||||||
messages.value.push({
|
debugger
|
||||||
from: 'ai-model',
|
if(!username) return Message.error('请先登录!')
|
||||||
type: '',
|
if(CONV_ID.value) {
|
||||||
content: '',
|
messages.value.push({
|
||||||
avatarPosition: 'side-left',
|
role: 'ai-model',
|
||||||
avatarConfig: { ...aiModelAvatar },
|
type: '',
|
||||||
loading: true,
|
content: '',
|
||||||
});
|
avatarPosition: 'side-left',
|
||||||
|
avatarConfig: { ...aiModelAvatar },
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
|
||||||
const {data} = await axios.get(VITE_AI_API_HOST + '/api/v0/chat_use_sql?question='+content);
|
const response = await axios.post(`${VITE_AI_API_HOST}/api/v0/chat_use_sql`, {
|
||||||
const {text,type} = data;
|
userId: username, // 使用 username 作为 userId
|
||||||
|
conversationId: CONV_ID.value,
|
||||||
|
question: content,
|
||||||
|
});
|
||||||
|
|
||||||
if(type==='text') {
|
if(response.data.type) {
|
||||||
messages.value[messages.value.length - 1].content = text;
|
const {text,type} = response.data;
|
||||||
messages.value[messages.value.length - 1].loading = false;
|
|
||||||
messages.value[messages.value.length - 1].type = 'text';
|
if(type==='text') {
|
||||||
} else if(type==='df') {
|
messages.value[messages.value.length - 1].content = text;
|
||||||
messages.value[messages.value.length - 1].content = data[type];
|
messages.value[messages.value.length - 1].loading = false;
|
||||||
messages.value[messages.value.length - 1].loading = false;
|
messages.value[messages.value.length - 1].type = 'text';
|
||||||
messages.value[messages.value.length - 1].type = 'df';
|
} else if(type==='df') {
|
||||||
|
messages.value[messages.value.length - 1].content = response.data[type];
|
||||||
|
messages.value[messages.value.length - 1].loading = false;
|
||||||
|
messages.value[messages.value.length - 1].type = 'df';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Message.warning('接口异常!')
|
||||||
|
}
|
||||||
|
// messages.value.push({
|
||||||
|
// from: 'ai-model',
|
||||||
|
// content: '',
|
||||||
|
// avatarPosition: 'side-left',
|
||||||
|
// avatarConfig: { ...aiModelAvatar },
|
||||||
|
// loading: true,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// /* 模拟流式数据返回 */
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// messages.value.at(-1).loading = false;
|
||||||
|
// for (let i = 0; i < content.length;) {
|
||||||
|
// await new Promise(r => setTimeout(r, 300 * Math.random()));
|
||||||
|
// messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10);
|
||||||
|
// nextTick(() => {
|
||||||
|
// conversationRef.value?.scrollTo({
|
||||||
|
// top: conversationRef.value.scrollHeight
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }, 1000);
|
||||||
|
} else {
|
||||||
|
Message.error('请先创建会话!');
|
||||||
}
|
}
|
||||||
// messages.value.push({
|
};
|
||||||
// from: 'ai-model',
|
|
||||||
// content: '',
|
|
||||||
// avatarPosition: 'side-left',
|
|
||||||
// avatarConfig: { ...aiModelAvatar },
|
|
||||||
// loading: true,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// /* 模拟流式数据返回 */
|
const viewHistoryRef = ref(null);
|
||||||
// setTimeout(async () => {
|
// 当前会话id
|
||||||
// messages.value.at(-1).loading = false;
|
const CONV_ID = ref('');
|
||||||
// for (let i = 0; i < content.length;) {
|
// 创建对话接口
|
||||||
// await new Promise(r => setTimeout(r, 300 * Math.random()));
|
const createConversation = async () => {
|
||||||
// messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10);
|
try {
|
||||||
// nextTick(() => {
|
if (!username) {
|
||||||
// conversationRef.value?.scrollTo({
|
Message.error('请先登录!');
|
||||||
// top: conversationRef.value.scrollHeight
|
return;
|
||||||
// });
|
}
|
||||||
// });
|
const response = await axios.post(`${VITE_AI_API_HOST}/api/createConversation`, {
|
||||||
// }
|
userId: username,
|
||||||
// }, 1000);
|
});
|
||||||
|
debugger
|
||||||
|
const createRes = response.data;
|
||||||
|
|
||||||
|
if (createRes&&createRes.conversationId) {
|
||||||
|
CONV_ID.value = createRes.conversationId;
|
||||||
|
console.log('创建会话成功,会话ID:', CONV_ID.value);
|
||||||
|
nextTick(() => {
|
||||||
|
// 刷新会话列表
|
||||||
|
if (viewHistoryRef.value) {
|
||||||
|
viewHistoryRef.value.getQuestionHistory(); // 调用子组件方法
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Message.error('创建会话失败,未获取到会话ID');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建会话失败:', error);
|
||||||
|
Message.error('创建会话失败,请重试');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectConv = (convId: string) => {
|
||||||
|
CONV_ID.value = convId; // 更新为选中的会话 ID
|
||||||
|
getConversationDetail(convId); // 调用详情接口
|
||||||
|
};
|
||||||
|
|
||||||
|
// 定义获取会话详情的接口(根据实际接口调整)
|
||||||
|
const getConversationDetail = async (convId: string) => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${VITE_AI_API_HOST}/api/conversationDetail`, {
|
||||||
|
params: {
|
||||||
|
userId: username,
|
||||||
|
conversationId: convId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const detail = response.data;
|
||||||
|
// 处理详情数据(如回显消息列表)
|
||||||
|
handleDetailResponse(detail);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取会话详情失败:', error);
|
||||||
|
Message.error('获取会话详情失败,请重试');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理详情数据(示例:更新消息列表)
|
||||||
|
const handleDetailResponse = (detail: any) => {
|
||||||
|
// 假设接口返回消息列表为 messagesList
|
||||||
|
messages.value = detail.messages || [];
|
||||||
|
startChat.value = true; // 显示聊天界面
|
||||||
|
nextTick(() => {
|
||||||
|
conversationRef.value?.scrollTo({
|
||||||
|
top: conversationRef.value.scrollHeight,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onNewConvo = () => {
|
const onNewConvo = () => {
|
||||||
startChat.value = false;
|
startChat.value = false;
|
||||||
messages.value = [];
|
messages.value = [];
|
||||||
|
createConversation()
|
||||||
};
|
};
|
||||||
|
|
||||||
const onItemClick = (item) => {
|
const onItemClick = (item) => {
|
||||||
@@ -660,4 +776,51 @@ onMounted(() => {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.back-in-btn {
|
||||||
|
position: fixed;
|
||||||
|
left: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background-color: #f0f0f0; /* 灰色背景 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.active .icon {
|
||||||
|
transform: translateY(-4px); /* 图标上移4px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-in-time-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
background-color: var(--el-color-primary);
|
||||||
|
//color: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 999;
|
||||||
|
transition: all 0.3s;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-in-time-btn:hover {
|
||||||
|
background-color: var(--el-color-primary-light-3);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 - 移动端隐藏或调整位置 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.back-in-time-btn {
|
||||||
|
left: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user