|
|
@@ -1,78 +1,7 @@
|
|
|
<template>
|
|
|
<page-meta root-font-size="system" />
|
|
|
<view class="container">
|
|
|
- <scroll-view class="chat-messages" scroll-y="true" :scroll-with-animation="true"
|
|
|
- :scroll-into-view="scrollToView"
|
|
|
- :style="{ width: $scrollViewWidth + 'px', padding: $viewPadding + 'px', maxHeight: $viewMaxHeight + 'px' }">
|
|
|
- <!-- 循环渲染消息 -->
|
|
|
- <view v-for="(message, index) in messages" :key="index" :id="'msg' + index" style="clear: both;">
|
|
|
- <view :class="['message', message.sender === 'user' ? 'user-message' : 'ai-message']">
|
|
|
- <text :user-select="true" :selectable="true">{{ message.content }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <!-- 加载中 -->
|
|
|
- <view style="clear: both;" v-if="loadingButton">
|
|
|
- <view class="message ai-message">
|
|
|
- <button :loading="true" class="loading_button" type="default"></button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- <view class="chat-input">
|
|
|
- <textarea @linechange="chatMsgMaxHeightChange" auto-height v-model="inputMessage" placeholder="输入消息..."
|
|
|
- class="input-field" />
|
|
|
- <button class="send-button" :disabled="!buttonState" @click="sendMessage">发送</button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="fab_button">
|
|
|
- <view class="history_button">
|
|
|
- <uni-fab :pattern="{ icon: 'list' }" :popMenu="false" horizontal="right" vertical="bottom"
|
|
|
- @fabClick="showHistorySession()"></uni-fab>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="drawer_container">
|
|
|
- <uni-drawer ref="showLeftDrawer" :width="220">
|
|
|
- <view>
|
|
|
- <scroll-view scroll-y="true" :style="{height: '100vh'}">
|
|
|
- <view class="list_container">
|
|
|
- <uni-list>
|
|
|
- <uni-list-item title="新建会话" :clickable="true" @click="createSession()">
|
|
|
- <template v-slot:footer>
|
|
|
- <uni-icons type="plus-filled" size="24"></uni-icons>
|
|
|
- </template>
|
|
|
- </uni-list-item>
|
|
|
- <view v-for="(session,index) in sessionList" :key="index">
|
|
|
- <uni-list-item :title="session.sessionName" :clickable="true"
|
|
|
- @click="changeSession(session.sessionId)" :ellipsis="2">
|
|
|
- <template v-slot:footer>
|
|
|
- <uni-icons type="compose" size="24"
|
|
|
- @click.stop.prevent="toEditSession(session)"></uni-icons>
|
|
|
- </template>
|
|
|
- </uni-list-item>
|
|
|
- </view>
|
|
|
- </uni-list>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- </uni-drawer>
|
|
|
- </view>
|
|
|
- <view class="edit_popup">
|
|
|
- <uni-popup ref="editPopup" type="center" :mask-click="true">
|
|
|
- <view class="edit_session_container">
|
|
|
- <uni-card title="编辑会话信息">
|
|
|
- <uni-forms ref="editForm" :modelValue="editSession" :rules="rules">
|
|
|
- <uni-forms-item label="会话名" name="sessionName">
|
|
|
- <uni-easyinput type="textarea" v-model="editSession.sessionName" placeholder="请输入会话名" />
|
|
|
- </uni-forms-item>
|
|
|
- <uni-forms-item>
|
|
|
- <button type="primary" :disabled="!editButtonState" @click="submitEditSession()">确认</button>
|
|
|
- </uni-forms-item>
|
|
|
- <uni-forms-item>
|
|
|
- <button type="warn" :disabled="!editButtonState" @click="deleteSession()">删除</button>
|
|
|
- </uni-forms-item>
|
|
|
- </uni-forms>
|
|
|
- </uni-card>
|
|
|
- </view>
|
|
|
- </uni-popup>
|
|
|
+ <web-view :src="'https://api.ygtxfj.com:3443/auth?token=' + token"></web-view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -83,181 +12,16 @@ import {
|
|
|
onMounted,
|
|
|
reactive
|
|
|
} from 'vue';
|
|
|
-import $modal from '@/plugins/modal.js'
|
|
|
import { useUserStore } from '@/store/user.js'
|
|
|
-import { sendMessageToAI, getSessionList, getMessageList, setSessionName, delSession } from '@/api/AI.js'
|
|
|
-
|
|
|
+import { getToken } from '@/api/AI.js'
|
|
|
+const token = ref('')
|
|
|
+const userStore = useUserStore()
|
|
|
onMounted(() => {
|
|
|
// 在组件挂载后获取窗口高度
|
|
|
- const res = uni.getWindowInfo();
|
|
|
- // 计算滚动视图宽度
|
|
|
- $scrollViewWidth.value = res.windowWidth - $viewPadding.value * 2;
|
|
|
- $windowHeight.value = res.windowHeight;
|
|
|
- $viewMaxHeight.value = res.windowHeight - 100;
|
|
|
- initHistorySession()
|
|
|
-});
|
|
|
-// 弹出会话列表侧边栏
|
|
|
-const showLeftDrawer = ref(null)
|
|
|
-function showHistorySession() {
|
|
|
- showLeftDrawer.value.open()
|
|
|
-}
|
|
|
-// 初始化会话列表
|
|
|
-const userStore = useUserStore()
|
|
|
-const sessionList = reactive([])
|
|
|
-function initHistorySession() {
|
|
|
- sessionList.length = 0
|
|
|
- getSessionList(userStore.user.useId).then(({ returnParams }) => {
|
|
|
- sessionList.push(...returnParams)
|
|
|
+ getToken(userStore.user.useId).then(({ returnParams }) => {
|
|
|
+ token.value = returnParams.aiToken
|
|
|
})
|
|
|
-}
|
|
|
-// 新建会话
|
|
|
-function createSession() {
|
|
|
- messages.length = 0
|
|
|
- thisSessionId.value = 0
|
|
|
- showLeftDrawer.value.close()
|
|
|
-}
|
|
|
-// 切换会话
|
|
|
-function changeSession(sessionId) {
|
|
|
- thisSessionId.value = sessionId
|
|
|
- initHistoryMessage(sessionId)
|
|
|
-}
|
|
|
-// 修改会话信息
|
|
|
-const editSession = ref({})
|
|
|
-const editPopup = ref(null)
|
|
|
-const editButtonState = ref(true)
|
|
|
-function toEditSession(session) {
|
|
|
- showLeftDrawer.value.close()
|
|
|
- editSession.value = session
|
|
|
- editPopup.value.open()
|
|
|
-}
|
|
|
-function submitEditSession() {
|
|
|
- editButtonState.value = false
|
|
|
- setSessionName(editSession.value).then(res => {
|
|
|
- initHistorySession()
|
|
|
- editPopup.value.close()
|
|
|
- editButtonState.value = true
|
|
|
- })
|
|
|
-}
|
|
|
-function deleteSession() {
|
|
|
- editButtonState.value = false
|
|
|
- $modal.confirm("确认删除").then(res => {
|
|
|
- delSession(editSession.value.sessionId).then(res => {
|
|
|
- initHistorySession()
|
|
|
- createSession()
|
|
|
- editPopup.value.close()
|
|
|
- editButtonState.value = true
|
|
|
- })
|
|
|
- })
|
|
|
- .catch(res => {
|
|
|
- editButtonState.value = true
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- const messages = reactive([{
|
|
|
- sender: 'assistant',
|
|
|
- content: '您好,我是ai助手'
|
|
|
- }
|
|
|
- ]);
|
|
|
-function initHistoryMessage(sessionId) {
|
|
|
- getMessageList(sessionId).then(res => {
|
|
|
- const returnParams = res.returnParams
|
|
|
- messages.length = 0
|
|
|
- for (let i = 0; i < returnParams.length; i++) {
|
|
|
- const item = returnParams[i]
|
|
|
- messages.push({
|
|
|
- sender: 'user',
|
|
|
- content: item.sendContent
|
|
|
- })
|
|
|
- messages.push({
|
|
|
- sender: 'assistant',
|
|
|
- content: item.receiveContent
|
|
|
- })
|
|
|
- }
|
|
|
- scrollToBottom(); // 滚动到底部
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
- const thisSessionId = ref(0);
|
|
|
- const inputMessage = ref('');
|
|
|
- const scrollToView = ref('');// 滚动到特定消息的标识
|
|
|
- const buttonState = ref(true)
|
|
|
- const loadingButton = ref(false)
|
|
|
-
|
|
|
- // 发送消息函数
|
|
|
- function sendMessage() {
|
|
|
- buttonState.value = false
|
|
|
- if (inputMessage.value.trim() === '') {
|
|
|
- buttonState.value = true
|
|
|
- return;
|
|
|
- }
|
|
|
- messages.push({
|
|
|
- sender: 'user',
|
|
|
- content: inputMessage.value
|
|
|
- });
|
|
|
- loadingButton.value = true
|
|
|
- scrollToBottom(); // 滚动到底部
|
|
|
- const message = {
|
|
|
- sessionId: thisSessionId.value,
|
|
|
- prompt: inputMessage.value,
|
|
|
- userId: userStore.user.useId,
|
|
|
- sort: messages.filter(item => item.sender == 'user').length
|
|
|
- }
|
|
|
- sendMessageToAI(message).then((res) => {
|
|
|
- const returnParams = res.returnParams
|
|
|
- if (thisSessionId.value == 0) { // 添加新会话
|
|
|
- thisSessionId.value = returnParams.sessionId // 新会话ID
|
|
|
- sessionList.unshift({
|
|
|
- sessionName: returnParams.sessionName,
|
|
|
- sessionId: returnParams.sessionId
|
|
|
- })
|
|
|
- } else {
|
|
|
- initHistorySession()
|
|
|
- }
|
|
|
- inputMessage.value = ''; // 清空输入框
|
|
|
- loadingButton.value = false
|
|
|
- if (thisSessionId.value != returnParams.sessionId) {
|
|
|
- buttonState.value = true;
|
|
|
- return
|
|
|
- }
|
|
|
- let content = ""
|
|
|
- const index = messages.length // 新增消息索引
|
|
|
- messages.push({ //
|
|
|
- sender: 'assistant',
|
|
|
- content: content
|
|
|
- });
|
|
|
- let i = 0
|
|
|
- const charLength = 3 // 每次显示字数
|
|
|
- const messageLength = returnParams.receiveContent.length
|
|
|
- const interval = setInterval(() => { //模拟流式输出
|
|
|
- if (i < messageLength) {
|
|
|
- let sliceLength = i + charLength > messageLength?messageLength:i + charLength // 当前显示字数
|
|
|
- messages[index].content += returnParams.receiveContent.slice(i, sliceLength); // 每次输出 3 个字符
|
|
|
- i += charLength;
|
|
|
- } else {
|
|
|
- clearInterval(interval);
|
|
|
- buttonState.value = true;
|
|
|
- }
|
|
|
- }, 50); // 50ms 一次
|
|
|
- })
|
|
|
- };
|
|
|
-
|
|
|
- // 滚动到底部的函数
|
|
|
- function scrollToBottom() {
|
|
|
- nextTick(() => {
|
|
|
- scrollToView.value = 'msg' + (messages.length - 1); // 更新滚动到的消息
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- const $scrollViewWidth = ref(0); // 滚动视图宽度
|
|
|
- const $viewMaxHeight = ref(0); // 滚动视图最大高度
|
|
|
- const $viewPadding = ref(10); // 滚动视图内边距
|
|
|
- const $windowHeight = ref(0); // 窗口高度
|
|
|
-
|
|
|
- // 输入框行数变化时更新最大高度
|
|
|
- function chatMsgMaxHeightChange(e) {
|
|
|
- // console.log($windowHeight,e.detail.height);
|
|
|
- $viewMaxHeight.value = $windowHeight.value - e.detail.height - 70;
|
|
|
- }
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
|
|
|
@@ -267,123 +31,5 @@ function initHistoryMessage(sessionId) {
|
|
|
flex-direction: column;
|
|
|
height: 100vh;
|
|
|
position: relative;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-.chat-messages {
|
|
|
- flex: 1;
|
|
|
- background-color: #f3f3f3;
|
|
|
- overflow-y: auto;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-.message {
|
|
|
- max-width: 70%;
|
|
|
- margin: 5px 0;
|
|
|
- padding: 8px;
|
|
|
- border-radius: 10px;
|
|
|
- display: inline-block;
|
|
|
- word-wrap: break-word;
|
|
|
-}
|
|
|
-
|
|
|
-.loading_button {
|
|
|
- background-color: #ECECEC !important;
|
|
|
-}
|
|
|
-.loading_button::after {
|
|
|
- border: 0px;
|
|
|
}
|
|
|
-
|
|
|
-.user-message {
|
|
|
- background-color: #DCF8C6;
|
|
|
- align-self: flex-end;
|
|
|
- float: right;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-message {
|
|
|
- background-color: #ECECEC;
|
|
|
- align-self: flex-start;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-input {
|
|
|
- display: flex;
|
|
|
- padding: 10px;
|
|
|
- background-color: #FFFFFF;
|
|
|
- border-top: 1px solid #E0E0E0;
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.input-field {
|
|
|
- flex: 1;
|
|
|
- border: 1px solid #E0E0E0;
|
|
|
- border-radius: 20px;
|
|
|
- padding: 12px;
|
|
|
- margin-right: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.send-button {
|
|
|
- border: none;
|
|
|
- border-radius: 20px;
|
|
|
- padding: 0 20px;
|
|
|
- background-color: #007AFF;
|
|
|
- color: white;
|
|
|
- height: 46px;
|
|
|
- }
|
|
|
-
|
|
|
- .fab_button {
|
|
|
- ::v-deep .history_button {
|
|
|
- .uni-fab__circle {
|
|
|
- bottom: 100px !important;
|
|
|
- }
|
|
|
- .uni-fab__circle {
|
|
|
- width: calc(55px + .5*(1rem - 16px)) !important;
|
|
|
- height: calc(55px + .5*(1rem - 16px)) !important;
|
|
|
-
|
|
|
- .uni-icons {
|
|
|
- font-size: calc(32px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .drawer_container {
|
|
|
- ::v-deep .list_container {
|
|
|
- .uni-list-item__content {
|
|
|
- .uni-list-item__content-title {
|
|
|
- font-size: calc(14px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- }
|
|
|
- .uni-icons {
|
|
|
- font-size: calc(24px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- .edit_popup {
|
|
|
- ::v-deep .edit_session_container {
|
|
|
- .uni-card__header {
|
|
|
- .uni-card__header-content-title {
|
|
|
- font-size: calc(15px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- }
|
|
|
- .uni-card__content {
|
|
|
- .uni-forms-item {
|
|
|
- .uni-forms-item__label {
|
|
|
- font-size: calc(14px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- .uni-forms-item__content {
|
|
|
- .uni-easyinput {
|
|
|
- .uni-easyinput__content-textarea {
|
|
|
- font-size: calc(14px + .5*(1rem - 16px)) !important;
|
|
|
- min-width: 200px;
|
|
|
- }
|
|
|
- .uni-icons {
|
|
|
- font-size: calc(24px + .5*(1rem - 16px)) !important;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
</style>
|