| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- <script setup lang="ts">
- import {
- IconSearch,
- IconTiktokColor,
- IconSend,
- IconClose,
- } from '@arco-design/web-vue/es/icon';
- import { useAppStore } from '@/store';
- import { computed, ref, onMounted, reactive, nextTick } from 'vue';
- import { Message } from '@arco-design/web-vue';
- import moment from 'moment';
- import AddSession from '@/views/session/sessionManager/components/addSession.vue';
- import {
- sessionListApi,
- deleteSessionApi,
- getSessionDetailsApi,
- chatApi,
- } from '@/api/session';
- const sessionDetailList = ref([]); //根据会话id出来的会话详情
- const sessionList = ref([]); //会话列表
- const modalObj = reactive({ add: false });
- const currIndex = ref(0);
- const displayedText = ref(''); // 正在显示的文字
- let timer: number | null = null;
- const streamStr = ref('');
- const inputMsg = ref('');
- const activeSessionId = ref('');
- const sendMessage = async (event) => {
- event.preventDefault();
- if (!activeSessionId.value) {
- Message.warning('请选择会话');
- return;
- }
- if (inputMsg.value) {
- const { code, data } = await chatApi({
- conversation_id: activeSessionId.value,
- messages: inputMsg.value,
- });
- const res = await getSessionDetailsApi(activeSessionId.value);
- if (res.code === 200) {
- sessionDetailList.value = res.data.message.map((item, index) => {
- if (index === res.data.message.length - 1) {
- item.role = 'last';
- displayedText.value = '';
- currIndex.value = 0;
- streamStr.value = item.content;
- startDisplayStr();
- }
- return item;
- });
- refreshScroll();
- }
- inputMsg.value = '';
- } else {
- Message.warning('消息不能为空');
- }
- };
- const querySessionDetail = async (session) => {
- activeSessionId.value = session.id;
- const { code, data } = await getSessionDetailsApi(session.id);
- if (code === 200) {
- sessionDetailList.value = data.message;
- refreshScroll(); //刷新滚动条位置
- }
- };
- const scrollbar = ref(null);
- const refreshScroll = () => {
- nextTick(() => {
- const container = document.getElementById('home');
- scrollbar.value.scrollTop(container.scrollHeight);
- });
- };
- // 查询会话列表
- const querySessionList = async () => {
- const { code, data } = await sessionListApi();
- if (code === 200) {
- sessionList.value = data;
- } else {
- Message.warning('查询失败');
- }
- };
- //新增会话之后刷新会话列表
- const addSession = () => {
- querySessionList();
- };
- onMounted(() => {
- querySessionList();
- });
- const appStore = useAppStore();
- const theme = computed(() => {
- return appStore.theme;
- });
- //文字动态输出
- const startDisplayStr = () => {
- if (timer) {
- clearTimeout(timer!);
- }
- const res = streamStr.value;
- // 将数组中的字符串拼接起来
- if (currIndex.value < res.length) {
- displayedText.value += res[currIndex.value];
- currIndex.value++;
- setTimeout(startDisplayStr, 100);
- } else {
- clearTimeout(timer!);
- timer = null;
- }
- };
- </script>
- <template>
- <div class="container">
- <AddSession :modalObj="modalObj" @addSession="addSession"></AddSession>
- <a-card class="top-title">AI会话记录</a-card>
- <a-row :gutter="[5, 5]" style="margin-top: 3px">
- <a-col :span="4">
- <a-card style="height: 60px">
- <template #cover>
- <div style="display: flex; justify-content: space-between">
- <a-button
- type="primary"
- shape="round"
- class="card-btn-1"
- @click="modalObj.add = true"
- >
- +新建会话
- </a-button>
- <a-button type="text" shape="circle" class="card-btn-2">
- <icon-search />
- </a-button>
- </div>
- </template>
- </a-card>
- <a-card class="left">
- <a-scrollbar
- class="left-list"
- style="
- height: calc(100vh - 160px);
- overflow-y: auto;
- overflow-x: hidden;
- "
- >
- <div
- class="item"
- v-for="session in sessionList"
- @click="querySessionDetail(session)"
- :class="{ isLeftActive: activeSessionId === session.id }"
- >
- <div class="text" :class="{ light: theme === 'dark' }">{{
- session.name
- }}</div>
- <div class="time">{{
- moment(new Date(session.create_time)).format(
- 'YYYY-MM-DD HH:mm:ss'
- )
- }}</div>
- </div>
- </a-scrollbar>
- </a-card>
- </a-col>
- <a-col :span="15">
- <a-card class="center">
- <div v-if="sessionDetailList.length === 0">
- <div class="center-title">智能问答</div>
- <div class="center-content">
- 我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~
- </div>
- <div class="center-question">
- <div class="center-question-left">试一试这样问我</div>
- <div class="center-question-right">
- <a-button type="primary">换一换</a-button>
- </div>
- </div>
- <a-row justify="space-around" class="center-list">
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </a-col>
- </a-row>
- </div>
- <a-scrollbar
- ref="scrollbar"
- id="home"
- v-else
- class="chat-list"
- style="width: 90%; overflow: auto; height: 60vh; margin: 0px auto"
- >
- <div class="chat-item" v-for="sessionDetail in sessionDetailList">
- <a-comment
- v-if="sessionDetail.role === 'user'"
- avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
- >
- <template #content>
- <div :class="{ light: theme === 'light' }">{{
- sessionDetail.content
- }}</div>
- </template>
- </a-comment>
- <a-comment
- v-else-if="sessionDetail.role === 'assistant'"
- avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp"
- >
- <template #content>
- <a-card
- class="chat-item-answer"
- style="background-color: rgba(63, 64, 79, 1)"
- >
- <div :class="{ light: theme === 'light' }">{{
- sessionDetail.content
- }}</div>
- </a-card>
- </template>
- </a-comment>
- <a-comment
- v-else-if="sessionDetail.role === 'last'"
- avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp"
- >
- <template #content>
- <a-textarea
- readonly
- auto-size
- v-model="displayedText"
- class="chat-item-answer"
- style="background-color: rgba(63, 64, 79, 1)"
- >
- </a-textarea>
- </template>
- </a-comment>
- </div>
- </a-scrollbar>
- <div class="center-bottom">
- <a-textarea
- v-model="inputMsg"
- @keydown.shift.enter="sendMessage"
- style="height: 180px"
- placeholder="输入您想了解的内容,Shift+Enter发送"
- :max-length="500"
- allow-clear
- show-word-limit
- >
- </a-textarea>
- </div>
- </a-card>
- </a-col>
- <a-col :span="5">
- <a-card class="right">
- <div class="right-top">
- <div class="right-title">数智库</div>
- <div class="right-btn">
- <a-button type="outline" shape="circle" style="border: none">
- <icon-search />
- </a-button>
- <a-button
- type="outline"
- shape="circle"
- style="border: none; margin-left: -10px"
- >
- <icon-close />
- </a-button>
- </div>
- </div>
- <div class="right-tag">
- <a-space>
- <a-button type="primary" shape="round" size="mini" class="btn"
- >全部</a-button
- >
- <a-button type="outline" shape="round" size="mini" class="btn"
- >文档创作</a-button
- >
- <a-button type="outline" shape="round" size="mini" class="btn"
- >知识学习</a-button
- >
- </a-space>
- <a-space style="margin-top: 10px">
- <a-button type="outline" shape="round" size="mini" class="btn"
- >效率提升</a-button
- >
- </a-space>
- </div>
- <div class="right-list">
- <div class="right-item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </div>
- <div class="right-item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </div>
- <div class="right-item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>抖音带货脚本
- </div>
- <div class="item-content" :class="{ dark: theme === 'dark' }">
- 编写引人注目且具有说服力的、适用于产品的...
- </div>
- </div>
- </div>
- </a-card>
- </a-col>
- </a-row>
- </div>
- </template>
- <style scoped lang="scss">
- .isLeftActive {
- background-color: lightgrey;
- }
- .light {
- color: white !important;
- }
- .dark {
- color: gray !important;
- }
- .container {
- .top-title {
- line-height: 60px;
- font-size: 25px;
- font-family: 黑体;
- }
- .center,
- .right {
- box-sizing: border-box;
- height: calc(100vh - 100px);
- }
- .left {
- /* height: calc(100vh - 160px);
- overflow-y: auto;
- overflow-x: hidden;*/
- border: 0px;
- .left-list {
- .item {
- cursor: pointer;
- .text,
- .time {
- line-height: 30px;
- }
- .text {
- color: black;
- padding-left: 10px;
- }
- .time {
- color: gray;
- font-size: 12px;
- padding-left: 10px;
- }
- }
- }
- }
- .card-btn-1 {
- margin: 10px;
- width: 75%;
- }
- .card-btn-2 {
- margin: 10px 10px;
- }
- .center {
- position: relative;
- .center-title {
- line-height: 60px;
- font-size: 25px;
- font-family: 黑体;
- color: deepskyblue;
- }
- .center-content {
- font-size: 14px;
- color: gray;
- }
- .center-question {
- margin-top: 20px;
- display: flex;
- justify-content: space-between;
- .center-question-left {
- margin-top: 5px;
- margin-left: 20px;
- }
- .center-question-right {
- margin-right: 20px;
- }
- }
- .center-list {
- margin-top: 10px;
- .item {
- border-radius: 10px;
- margin-top: 10px;
- padding: 10px;
- height: 120px;
- background-color: lightcyan;
- .item-title {
- text-align: center;
- line-height: 40px;
- font-size: 20px;
- font-family: 黑体;
- color: black;
- }
- }
- }
- .center-bottom {
- position: absolute;
- width: 90%;
- bottom: 20px;
- left: 5%;
- }
- }
- .right {
- .right-top {
- display: flex;
- justify-content: space-between;
- .right-title {
- font-size: 25px;
- font-family: 黑体;
- color: black;
- }
- .right-btn {
- position: relative;
- left: 20px;
- top: 0px;
- }
- }
- .right-tag {
- margin-top: 20px;
- }
- .right-list {
- .right-item {
- border-radius: 10px;
- margin-top: 10px;
- padding: 10px;
- height: 120px;
- background-color: lightcyan;
- .item-title {
- text-align: center;
- line-height: 40px;
- font-size: 20px;
- font-family: 黑体;
- color: black;
- }
- }
- }
- }
- }
- </style>
|