mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	1. 发起 socket 连接时候传入 chatId 来区分会话。
2. Chat-Plus 界面新增复制回复内容按钮。 3. 优化 ChatFree 聊天会话切换和管理逻辑。
This commit is contained in:
		@@ -29,7 +29,9 @@ func (s *Server) ChatHandle(c *gin.Context) {
 | 
			
		||||
	}
 | 
			
		||||
	sessionId := c.Query("sessionId")
 | 
			
		||||
	roleKey := c.Query("role")
 | 
			
		||||
	chatId := c.Query("chatId")
 | 
			
		||||
	session, ok := s.ChatSession[sessionId]
 | 
			
		||||
	session.ChatId = chatId
 | 
			
		||||
	if !ok { // 用户未登录
 | 
			
		||||
		c.Abort()
 | 
			
		||||
		return
 | 
			
		||||
@@ -61,18 +63,18 @@ func (s *Server) ChatHandle(c *gin.Context) {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			logger.Info("Receive a message: ", string(message))
 | 
			
		||||
			//replyMessage(client, "当前 TOKEN 无效,请使用合法的 TOKEN 登录!", false)
 | 
			
		||||
			//replyMessage(client, "", true)
 | 
			
		||||
			ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
			s.ReqCancelFunc[sessionId] = cancel
 | 
			
		||||
			// 回复消息
 | 
			
		||||
			err = s.sendMessage(ctx, session, chatRole, string(message), client, false)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logger.Error(err)
 | 
			
		||||
			} else {
 | 
			
		||||
				replyChunkMessage(client, types.WsMessage{Type: types.WsEnd, IsHelloMsg: false})
 | 
			
		||||
				logger.Info("回答完毕: " + string(message))
 | 
			
		||||
			}
 | 
			
		||||
			replyMessage(client, "当前 TOKEN 无效,请使用合法的 TOKEN 登录!", false)
 | 
			
		||||
			replyMessage(client, "", false)
 | 
			
		||||
			//ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
			//s.ReqCancelFunc[sessionId] = cancel
 | 
			
		||||
			//// 回复消息
 | 
			
		||||
			//err = s.sendMessage(ctx, session, chatRole, string(message), client, false)
 | 
			
		||||
			//if err != nil {
 | 
			
		||||
			//	logger.Error(err)
 | 
			
		||||
			//} else {
 | 
			
		||||
			//	replyChunkMessage(client, types.WsMessage{Type: types.WsEnd, IsHelloMsg: false})
 | 
			
		||||
			//	logger.Info("回答完毕: " + string(message))
 | 
			
		||||
			//}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
@@ -94,20 +96,20 @@ func (s *Server) sendMessage(ctx context.Context, session types.ChatSession, rol
 | 
			
		||||
 | 
			
		||||
	if user.Status == false {
 | 
			
		||||
		replyMessage(ws, "当前 TOKEN 已经被禁用,如果疑问,请联系管理员!", false)
 | 
			
		||||
		replyMessage(ws, "", true)
 | 
			
		||||
		replyMessage(ws, "", false)
 | 
			
		||||
		return errors.New("当前 TOKEN " + user.Name + "已经被禁用")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if time.Now().Unix() > user.ExpiredTime {
 | 
			
		||||
		exTime := time.Unix(user.ExpiredTime, 0).Format("2006-01-02 15:04:05")
 | 
			
		||||
		replyMessage(ws, "当前 TOKEN 已过期,过期时间为:"+exTime+",如果疑问,请联系管理员!", false)
 | 
			
		||||
		replyMessage(ws, "", true)
 | 
			
		||||
		replyMessage(ws, "", false)
 | 
			
		||||
		return errors.New("当前 TOKEN " + user.Name + "已过期")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if user.MaxCalls > 0 && user.RemainingCalls <= 0 {
 | 
			
		||||
		replyMessage(ws, "当前 TOKEN 点数已经用尽,加入我们的知识星球可以免费领取点卡!", false)
 | 
			
		||||
		replyMessage(ws, "", true)
 | 
			
		||||
		replyMessage(ws, "", false)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	var req = types.ApiRequest{
 | 
			
		||||
@@ -117,7 +119,7 @@ func (s *Server) sendMessage(ctx context.Context, session types.ChatSession, rol
 | 
			
		||||
		Stream:      true,
 | 
			
		||||
	}
 | 
			
		||||
	var chatCtx []types.Message
 | 
			
		||||
	var ctxKey = fmt.Sprintf("%s-%s", session.SessionId, role.Key)
 | 
			
		||||
	var ctxKey = fmt.Sprintf("%s-%s-%s", session.SessionId, role.Key, session.ChatId)
 | 
			
		||||
	if v, ok := s.ChatContexts[ctxKey]; ok && s.Config.Chat.EnableContext {
 | 
			
		||||
		chatCtx = v.Messages
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -190,7 +192,7 @@ func (s *Server) sendMessage(ctx context.Context, session types.ChatSession, rol
 | 
			
		||||
	// 如果三次请求都失败的话,则返回对应的错误信息
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		replyMessage(ws, ErrorMsg, false)
 | 
			
		||||
		replyMessage(ws, "", true)
 | 
			
		||||
		replyMessage(ws, "", false)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -237,7 +239,7 @@ func (s *Server) sendMessage(ctx context.Context, session types.ChatSession, rol
 | 
			
		||||
		if err != nil { // 数据解析出错
 | 
			
		||||
			logger.Error(err, line)
 | 
			
		||||
			replyMessage(ws, ErrorMsg, false)
 | 
			
		||||
			replyMessage(ws, "", true)
 | 
			
		||||
			replyMessage(ws, "", false)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -473,3 +475,18 @@ func (s *Server) StopGenerateHandle(c *gin.Context) {
 | 
			
		||||
	delete(s.ReqCancelFunc, sessionId)
 | 
			
		||||
	c.JSON(http.StatusOK, types.BizVo{Code: types.Success})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetHelloMsgHandle 获取角色的打招呼信息
 | 
			
		||||
func (s *Server) GetHelloMsgHandle(c *gin.Context) {
 | 
			
		||||
	role := strings.TrimSpace(c.Query("role"))
 | 
			
		||||
	if role == "" {
 | 
			
		||||
		c.JSON(http.StatusOK, types.BizVo{Code: types.InvalidParams, Message: "Invalid args"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	chatRole, err := GetChatRole(role)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Role not found"})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Data: chatRole.HelloMsg})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -94,6 +94,7 @@ func (s *Server) Run(webRoot embed.FS, path string, debug bool) {
 | 
			
		||||
	engine.POST("api/chat/stop", s.StopGenerateHandle)
 | 
			
		||||
	engine.POST("api/chat/history", s.GetChatHistoryHandle)
 | 
			
		||||
	engine.POST("api/chat/history/clear", s.ClearHistoryHandle)
 | 
			
		||||
	engine.GET("api/role/hello", s.GetHelloMsgHandle)
 | 
			
		||||
 | 
			
		||||
	engine.POST("api/config/set", s.ConfigSetHandle)
 | 
			
		||||
	engine.GET("api/config/chat-roles/get", s.GetChatRoleListHandle)
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ type ChatSession struct {
 | 
			
		||||
	SessionId string `json:"session_id"`
 | 
			
		||||
	ClientIP  string `json:"client_ip"` // 客户端 IP
 | 
			
		||||
	Username  string `json:"user"`      // 当前登录的 user
 | 
			
		||||
	ChatId    string `json:"chat_id"`   // 客户端聊天会话 ID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChatContext 聊天上下文
 | 
			
		||||
 
 | 
			
		||||
@@ -6,16 +6,34 @@
 | 
			
		||||
 | 
			
		||||
    <div class="chat-item">
 | 
			
		||||
      <div class="triangle"></div>
 | 
			
		||||
      <div class="content reply-content" :data-clipboard-text="orgContent" v-html="content"></div>
 | 
			
		||||
      <div class="content-box">
 | 
			
		||||
        <div class="content" v-html="content"></div>
 | 
			
		||||
        <div class="tool-box">
 | 
			
		||||
          <el-tooltip
 | 
			
		||||
              class="box-item"
 | 
			
		||||
              effect="light"
 | 
			
		||||
              content="复制回答"
 | 
			
		||||
              placement="bottom"
 | 
			
		||||
          >
 | 
			
		||||
            <el-button type="info" class="copy-reply" :data-clipboard-text="orgContent">
 | 
			
		||||
              <el-icon>
 | 
			
		||||
                <DocumentCopy/>
 | 
			
		||||
              </el-icon>
 | 
			
		||||
            </el-button>
 | 
			
		||||
          </el-tooltip>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {defineComponent} from "vue"
 | 
			
		||||
import {DocumentCopy} from "@element-plus/icons-vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'ChatReply',
 | 
			
		||||
  components: {DocumentCopy},
 | 
			
		||||
  props: {
 | 
			
		||||
    content: {
 | 
			
		||||
      type: String,
 | 
			
		||||
@@ -66,34 +84,49 @@ export default defineComponent({
 | 
			
		||||
        top: 13px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        min-height 20px;
 | 
			
		||||
        word-break break-word;
 | 
			
		||||
        padding: 12px 15px;
 | 
			
		||||
        color var(--content-color)
 | 
			
		||||
        background-color: #404042;
 | 
			
		||||
        font-size: var(--content-font-size);
 | 
			
		||||
        border-radius: 5px;
 | 
			
		||||
      .content-box {
 | 
			
		||||
 | 
			
		||||
        p {
 | 
			
		||||
          line-height 1.5
 | 
			
		||||
        display flex
 | 
			
		||||
        flex-direction row
 | 
			
		||||
 | 
			
		||||
          code {
 | 
			
		||||
            color #f1f1f1
 | 
			
		||||
            background-color #202121
 | 
			
		||||
            padding 0 3px;
 | 
			
		||||
            border-radius 5px;
 | 
			
		||||
        .content {
 | 
			
		||||
          min-height 20px;
 | 
			
		||||
          word-break break-word;
 | 
			
		||||
          padding: 12px 15px;
 | 
			
		||||
          color var(--content-color)
 | 
			
		||||
          background-color: #404042;
 | 
			
		||||
          font-size: var(--content-font-size);
 | 
			
		||||
          border-radius: 5px;
 | 
			
		||||
 | 
			
		||||
          p {
 | 
			
		||||
            line-height 1.5
 | 
			
		||||
 | 
			
		||||
            code {
 | 
			
		||||
              color #f1f1f1
 | 
			
		||||
              background-color #202121
 | 
			
		||||
              padding 0 3px;
 | 
			
		||||
              border-radius 5px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          p:last-child {
 | 
			
		||||
            margin-bottom: 0
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          p:first-child {
 | 
			
		||||
            margin-top 0
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p:last-child {
 | 
			
		||||
          margin-bottom: 0
 | 
			
		||||
        }
 | 
			
		||||
        .tool-box {
 | 
			
		||||
          padding-left 10px;
 | 
			
		||||
          font-size 16px;
 | 
			
		||||
 | 
			
		||||
        p:first-child {
 | 
			
		||||
          margin-top 0
 | 
			
		||||
          .el-button {
 | 
			
		||||
            height 20px
 | 
			
		||||
            padding 5px 2px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import Chat from "@/views/Chat.vue";
 | 
			
		||||
import NotFound from './views/404.vue'
 | 
			
		||||
import TestPage from './views/Test.vue'
 | 
			
		||||
import Home from "@/views/Home.vue";
 | 
			
		||||
import './utils/prototype'
 | 
			
		||||
import ChatFree from "@/views/ChatFree.vue";
 | 
			
		||||
 | 
			
		||||
const routes = [
 | 
			
		||||
 
 | 
			
		||||
@@ -72,3 +72,17 @@ export function dateFormat(timestamp, format) {
 | 
			
		||||
    }
 | 
			
		||||
    return timeDate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function arrayContains(array, value, compare) {
 | 
			
		||||
    if (typeof compare !== 'function') {
 | 
			
		||||
        compare = function (v1, v2) {
 | 
			
		||||
            return v1 === v2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    for (let i = 0; i < array.length; i++) {
 | 
			
		||||
        if (compare(array[i], value)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								web/src/utils/prototype.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								web/src/utils/prototype.js
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +0,0 @@
 | 
			
		||||
// add prototype method for array to insert item
 | 
			
		||||
Array.prototype.insert = function (index, item) {
 | 
			
		||||
  this.splice(index, 0, item)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Array.prototype.remove = function (index) {
 | 
			
		||||
  this.splice(index, 1)
 | 
			
		||||
}
 | 
			
		||||
@@ -21,12 +21,12 @@
 | 
			
		||||
            <span class="text" v-else>{{ chat.title }}</span>
 | 
			
		||||
 | 
			
		||||
            <span class="btn btn-check" v-if="chat.edit || chat.removing">
 | 
			
		||||
              <el-icon @click="confirm(chat)"><Check/></el-icon>
 | 
			
		||||
              <el-icon @click="cancel(chat)"><Close/></el-icon>
 | 
			
		||||
              <el-icon @click="confirm($event, chat)"><Check/></el-icon>
 | 
			
		||||
              <el-icon @click="cancel($event, chat)"><Close/></el-icon>
 | 
			
		||||
            </span>
 | 
			
		||||
            <span class="btn" v-else>
 | 
			
		||||
              <el-icon title="编辑" @click="editChatTitle(chat)"><Edit/></el-icon>
 | 
			
		||||
              <el-icon title="删除会话" @click="removeChat(chat)"><Delete/></el-icon>
 | 
			
		||||
              <el-icon title="编辑" @click="editChatTitle($event, chat)"><Edit/></el-icon>
 | 
			
		||||
              <el-icon title="删除会话" @click="removeChat($event, chat)"><Delete/></el-icon>
 | 
			
		||||
            </span>
 | 
			
		||||
 | 
			
		||||
          </a></li>
 | 
			
		||||
@@ -183,7 +183,7 @@ import {
 | 
			
		||||
  setLoginUser, removeChat, clearChatHistory
 | 
			
		||||
} from "@/utils/storage";
 | 
			
		||||
import {ElMessage, ElMessageBox} from "element-plus";
 | 
			
		||||
import {isMobile, randString} from "@/utils/libs";
 | 
			
		||||
import {arrayContains, isMobile, randString} from "@/utils/libs";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
 | 
			
		||||
// 免费版 ChatGPT
 | 
			
		||||
@@ -215,6 +215,7 @@ export default defineComponent({
 | 
			
		||||
      showLoginDialog: false,
 | 
			
		||||
      role: 'gpt',
 | 
			
		||||
      replyIcon: 'images/avatar/yi_yan.png', // 回复信息的头像
 | 
			
		||||
      helloMsg: '', // 打招呼信息
 | 
			
		||||
 | 
			
		||||
      chatList: [], // 会话列表
 | 
			
		||||
      tmpChatTitle: '',
 | 
			
		||||
@@ -264,9 +265,23 @@ export default defineComponent({
 | 
			
		||||
        this.inputBoxWidth = window.innerWidth - document.getElementById('sidebar').offsetWidth - 20;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    // 初始化打招呼信息
 | 
			
		||||
    httpGet("api/role/hello?role=" + this.role).then((res) => {
 | 
			
		||||
      this.helloMsg = {
 | 
			
		||||
        type: "reply",
 | 
			
		||||
        id: randString(32),
 | 
			
		||||
        icon: this.replyIcon,
 | 
			
		||||
        content: res.data,
 | 
			
		||||
      };
 | 
			
		||||
    })
 | 
			
		||||
    // 加载聊天列表
 | 
			
		||||
    const chatList = getChatList();
 | 
			
		||||
    if (chatList) {
 | 
			
		||||
      this.chatList = chatList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 创建新会话
 | 
			
		||||
    this.newChat();
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
@@ -284,7 +299,7 @@ export default defineComponent({
 | 
			
		||||
 | 
			
		||||
      // 初始化 WebSocket 对象
 | 
			
		||||
      const sessionId = getSessionId();
 | 
			
		||||
      const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`);
 | 
			
		||||
      const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}&chatId=${this.curChat.id}`);
 | 
			
		||||
      socket.addEventListener('open', () => {
 | 
			
		||||
        this.sending = false; // 允许用户发送消息
 | 
			
		||||
        this.loading = false; // 隐藏加载层
 | 
			
		||||
@@ -292,11 +307,10 @@ export default defineComponent({
 | 
			
		||||
          this.errorMessage.close(); // 关闭错误提示信息
 | 
			
		||||
        }
 | 
			
		||||
        this.activelyClose = false;
 | 
			
		||||
        // 加载聊天列表
 | 
			
		||||
        const chatList = getChatList();
 | 
			
		||||
        if (chatList) {
 | 
			
		||||
          this.chatList = chatList;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 显示打招呼信息
 | 
			
		||||
        this.chatData.push(this.helloMsg);
 | 
			
		||||
        this.fetchChatHistory(this.curChat.id);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      socket.addEventListener('message', event => {
 | 
			
		||||
@@ -305,11 +319,6 @@ export default defineComponent({
 | 
			
		||||
          reader.readAsText(event.data, "UTF-8");
 | 
			
		||||
          reader.onload = () => {
 | 
			
		||||
            const data = JSON.parse(String(reader.result));
 | 
			
		||||
            // 有聊天记录就不输出打招呼消息
 | 
			
		||||
            if (data['is_hello_msg'] && this.chatData.length > 1) {
 | 
			
		||||
              return
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (data.type === 'start') {
 | 
			
		||||
              this.chatData.push({
 | 
			
		||||
                type: "reply",
 | 
			
		||||
@@ -334,9 +343,14 @@ export default defineComponent({
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              this.showStopGenerate = false;
 | 
			
		||||
 | 
			
		||||
              this.lineBuffer = ''; // 清空缓冲
 | 
			
		||||
 | 
			
		||||
              // 追加会话
 | 
			
		||||
              if (this.curChat.title === '') {
 | 
			
		||||
                this.curChat.title = this.previousText;
 | 
			
		||||
                setChat(this.curChat);
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
              this.lineBuffer += data.content;
 | 
			
		||||
              this.chatData[this.chatData.length - 1]['orgContent'] = this.lineBuffer;
 | 
			
		||||
@@ -400,12 +414,11 @@ export default defineComponent({
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 从后端获取聊天历史记录
 | 
			
		||||
    // 加载聊天历史记录
 | 
			
		||||
    fetchChatHistory: function (chatId) {
 | 
			
		||||
      const list = getChatHistory(chatId);
 | 
			
		||||
      if (list) {
 | 
			
		||||
        const md = require('markdown-it')();
 | 
			
		||||
        console.log(list)
 | 
			
		||||
        for (let i = 0; i < list.length; i++) {
 | 
			
		||||
          if (list[i].type === "prompt") {
 | 
			
		||||
            this.chatData.push(list[i]);
 | 
			
		||||
@@ -562,16 +575,14 @@ export default defineComponent({
 | 
			
		||||
        if (chatHistory === null) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        this.curChat.title = chatHistory[0].content;
 | 
			
		||||
        // 追加会话
 | 
			
		||||
        setChat(this.curChat);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.appendChat();
 | 
			
		||||
      this.curChat = {
 | 
			
		||||
        id: randString(32),
 | 
			
		||||
        edit: false, // 是否处于编辑模式
 | 
			
		||||
        removing: false, // 是否处于删除模式
 | 
			
		||||
        title: '新会话 - 0'
 | 
			
		||||
        title: ''
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      this.chatData = [];
 | 
			
		||||
@@ -582,23 +593,39 @@ export default defineComponent({
 | 
			
		||||
      this.connect();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 追加当前会话到列表
 | 
			
		||||
    appendChat: function () {
 | 
			
		||||
      if (this.curChat !== null && this.curChat.title !== '') {
 | 
			
		||||
        const compare = function (v1, v2) {
 | 
			
		||||
          return v1.id === v2.id;
 | 
			
		||||
        }
 | 
			
		||||
        if (!arrayContains(this.chatList, this.curChat, compare)) {
 | 
			
		||||
          this.chatList[this.curChat.id] = this.curChat;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 编辑会话标题
 | 
			
		||||
    editChatTitle: function (chat) {
 | 
			
		||||
    editChatTitle: function (event, chat) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      chat.edit = true;
 | 
			
		||||
      this.curOpt = 'edit';
 | 
			
		||||
      this.tmpChatTitle = chat.title;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 确认修改
 | 
			
		||||
    confirm: function (chat) {
 | 
			
		||||
    confirm: function (event, chat) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      if (this.curOpt === 'edit') {
 | 
			
		||||
        chat.title = this.tmpChatTitle;
 | 
			
		||||
        chat.edit = false;
 | 
			
		||||
        setChat(chat)
 | 
			
		||||
      } else if (this.curOpt === 'remove') {
 | 
			
		||||
        delete this.chatList[chat.id];
 | 
			
		||||
        // 删除的会话是当前的聊天会话,则新建会话
 | 
			
		||||
        if (this.curChat.id === chat.id) {
 | 
			
		||||
          this.chatData = [];
 | 
			
		||||
          this.curChat = null;
 | 
			
		||||
          this.newChat();
 | 
			
		||||
        }
 | 
			
		||||
        removeChat(chat.id);
 | 
			
		||||
        chat.removing = false;
 | 
			
		||||
@@ -606,13 +633,15 @@ export default defineComponent({
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    // 取消修改
 | 
			
		||||
    cancel: function (chat) {
 | 
			
		||||
    cancel: function (event, chat) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      chat.edit = false;
 | 
			
		||||
      chat.removing = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 删除会话
 | 
			
		||||
    removeChat: function (chat) {
 | 
			
		||||
    removeChat: function (event, chat) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      chat.removing = true;
 | 
			
		||||
      this.curOpt = 'remove';
 | 
			
		||||
    },
 | 
			
		||||
@@ -623,8 +652,10 @@ export default defineComponent({
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.appendChat();
 | 
			
		||||
      this.chatData = [];
 | 
			
		||||
      this.curChat = chat;
 | 
			
		||||
      this.fetchChatHistory(chat.id);
 | 
			
		||||
      this.connect();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 退出登录
 | 
			
		||||
 
 | 
			
		||||
@@ -253,7 +253,7 @@ export default defineComponent({
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const clipboard = new Clipboard('.reply-content');
 | 
			
		||||
    const clipboard = new Clipboard('.copy-reply');
 | 
			
		||||
    clipboard.on('success', () => {
 | 
			
		||||
      ElMessage.success('复制成功!');
 | 
			
		||||
    })
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user