Files
ks-app-employment-service/stores/userChatGroupStore.js
2026-03-16 14:46:36 +08:00

431 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
defineStore
} from 'pinia';
import {
reactive,
ref,
toRaw
} from 'vue'
import baseDB from './BaseDBStore';
import {
msg,
CloneDeep,
$api,
formatDate,
insertSortData
} from '../common/globalFunction';
import {
UUID
} from '../lib/uuid-min';
import config from '../config';
import {
clearJobMoreMap
} from '@/utils/markdownParser';
const useChatGroupDBStore = defineStore("messageGroup", () => {
const tableName = ref('messageGroup')
const massageName = ref('messages')
const messages = ref([]) // 消息列表
const isTyping = ref(false) // 是否正在输入
const textInput = ref('')
// tabel
const tabeList = ref([])
const chatSessionID = ref('')
const lastDateRef = ref('')
async function init() {
// 获取所有数据
setTimeout(async () => {
if (!baseDB.isDBReady) await baseDB.initDB();
const result = await baseDB.db.getAll(tableName.value);
// 1、判断是否有数据没数据请求服务器
if (result.length) {
console.warn('本地数据库存在数据')
const list = result.reverse()
const [table, lastData] = insertSortData(list)
tabeList.value = table
const tabelRow = list[0]
chatSessionID.value = tabelRow.sessionId
initMessage(tabelRow.sessionId)
} else {
if (config.OnlyUseCachedDB) return;
console.warn('本地数据库不存在数据')
getHistory('refresh')
}
}, 1000)
}
async function initMessage(sessionId) {
if (!baseDB.isDBReady) await baseDB.initDB();
chatSessionID.value = sessionId
const list = await baseDB.db.queryByField(massageName.value, 'parentGroupId', sessionId);
clearJobMoreMap() // 清空对话 加载更多参数
if (list.length) {
console.log('本地数据库存在该对话数据', list)
messages.value = list
} else {
console.log('本地数据库不存在该对话数据')
getHistoryRecord('refresh')
}
}
async function addMessage(payload) {
if (!chatSessionID.value) {
return msg('请创建对话')
}
const params = {
...payload,
parentGroupId: chatSessionID.value,
files: payload.files || [],
}
messages.value.push(params);
addMessageIndexdb(params)
}
function toggleTyping(status) {
isTyping.value = status
}
async function addTabel(text) {
if (!baseDB.isDBReady) await baseDB.initDB();
const uuid = UUID.generate() // 对话sessionId
let payload = {
title: text,
createTime: formatDate(Date.now()),
sessionId: uuid
}
const id = await baseDB.db.add(tableName.value, payload);
const list = await baseDB.db.getAll(tableName.value);
chatSessionID.value = uuid
const [result, lastData] = insertSortData(list)
tabeList.value = result
return id
}
async function addMessageIndexdb(payload) {
return await baseDB.db.add(massageName.value, payload);
}
async function getStearm(text, fileUrls = [], progress, options = {}) {
return new Promise((resolve, reject) => {
try {
toggleTyping(true);
const customDataID = 'message_' + UUID.generate()
// 对话历史管理只保留最近的N条消息防止token超限
// 计算消息数量只保留最近的10条消息可根据实际情况调整
const MAX_HISTORY_MESSAGES = 10;
const historyMessages = messages.value.slice(-MAX_HISTORY_MESSAGES);
const params = {
data: text,
sessionId: chatSessionID.value,
dataId: customDataID
};
if (fileUrls && fileUrls.length) {
params['fileUrl'] = fileUrls.map((item) => item.url);
}
// ------>
const MsgData = {
text: text,
self: true,
displayText: text,
files: fileUrls
};
addMessage(MsgData); // 添加message数据
// <------
const newMsg = {
text: '', // 存储原始结构化内容
self: false,
displayText: '', // 用于流式渲染展示
dataId: customDataID
};
const index = messages.value.length;
messages.value.push(newMsg);
const rawParts = Array.isArray(text) ? text : [text]; // 统一处理
// 用于追加每个部分的流式数据
let partIndex = 0;
function handleUnload() {
newMsg.parentGroupId = chatSessionID.value;
baseDB.db.add(massageName.value, newMsg).then((id) => {
messages.value[index] = {
...newMsg,
id
};
});
}
// #ifdef H5
if (typeof window !== 'undefined') {
window.addEventListener("unload", handleUnload);
}
// #endif
function onDataReceived(data) {
// 支持追加多个部分
newMsg.text += data;
newMsg.displayText += data;
messages.value[index] = {
...newMsg
};
progress && progress();
// 调用外部传入的onDataReceived回调
if (options.onDataReceived) {
options.onDataReceived(data, newMsg, index);
}
}
function onError(error) {
msg('服务响应异常');
reject(error);
}
function onComplete() {
messages.value[index] = {
...newMsg
};
toggleTyping(false);
// #ifdef H5
if (typeof window !== 'undefined') {
window.removeEventListener("unload", handleUnload);
}
// #endif
handleUnload();
// 调用外部传入的onComplete回调
if (options.onComplete) {
options.onComplete();
}
resolve();
}
$api.streamRequest('/chat', params, onDataReceived, onError, onComplete);
} catch (err) {
console.log(err);
reject(err);
}
});
}
// 状态控制
function addNewDialogue() {
chatSessionID.value = ''
messages.value = []
}
function changeDialogue(item) {
chatSessionID.value = item.sessionId
initMessage(item.sessionId)
}
// 云端数据
function badFeedback(msgs, content = '') {
return new Promise((resolve, reject) => {
if (!msgs.dataId) {
return msg('旧数据没有dataId')
}
let parmas = {
dataId: msgs.dataId,
sessionId: msgs.parentGroupId,
userBadFeedback: content,
}
const dbData = {
...toRaw(msgs),
userBadFeedback: content,
}
$api.chatRequest('/stepped', parmas, 'POST').then((res) => {
baseDB.db.update(massageName.value, dbData) // 更新本地数据库
messages.value.forEach((item) => {
if (item.id === dbData.id) {
item.userBadFeedback = content
resolve()
}
})
})
})
}
// 云端数据
function getHistory() {
$api.chatRequest('/getHistory').then((res) => {
if (!res.data.list.length) return
let tabel = parseHistory(res.data.list)
if (tabel && tabel.length) {
const tabelRow = tabel[0] // 默认第一个
const [result, lastData] = insertSortData(tabel)
// console.log('getHistory insertSortData', result, lastData)
chatSessionID.value = tabelRow.sessionId
tabeList.value = result
getHistoryRecord(false)
baseDB.db.add(tableName.value, tabel);
lastDateRef.value = lastData
}
})
}
function getHistoryRecord(loading = true) {
const params = {
sessionId: chatSessionID.value
}
$api.chatRequest('/detail', params, 'GET', loading).then((res) => {
let list = parseHistoryDetail(res.data.list, chatSessionID.value)
if (list.length) {
baseDB.db.add(massageName.value, list).then((ids) => {
messages.value = listAddId(list, ids)
});
}
console.log('解析后:', list)
}).catch(() => {
msg('请求出现异常,请联系工作人员')
})
}
// 解析器
function parseHistory(list) {
return list.map((item) => ({
title: item.title,
createTime: item.updateTime,
sessionId: item.chatId
}))
}
function parseHistoryDetail(list, sessionId) {
const arr = []
for (let i = 0; i < list.length; i++) {
const element = list[i];
const self = element.obj !== 'AI'
let text = ''
let files = []
for (let j = 0; j < element.value.length; j++) {
const obj = element.value[j];
if (obj.type === 'text') {
text += obj.text.content
}
if (obj.type === 'file') {
files.push(obj.file)
}
if (obj.type === 'tool') {
console.log(obj)
}
}
arr.push({
parentGroupId: sessionId,
displayText: text,
self: self,
text: text,
userBadFeedback: element.userBadFeedback || '',
dataId: element.dataId,
files,
})
}
return arr
}
function listAddId(list, ids) {
return list.map((item, index) => ({
...item,
id: ids[index] || ids
}))
}
// 删除消息
async function deleteMessages(indices) {
// 按索引从大到小排序,避免删除时索引变化
const sortedIndices = [...indices].sort((a, b) => b - a);
// 从内存中删除消息
for (const index of sortedIndices) {
const message = messages.value[index];
if (message && message.id) {
// 从本地数据库中删除
await baseDB.db.delete(massageName.value, message.id);
}
messages.value.splice(index, 1);
}
}
// 删除会话
async function deleteDialogue(sessionId) {
if (!baseDB.isDBReady) await baseDB.initDB();
// 删除会话下的所有消息
const messageList = await baseDB.db.queryByField(massageName.value, 'parentGroupId', sessionId);
for (const message of messageList) {
if (message.id) {
await baseDB.db.delete(massageName.value, message.id);
}
}
// 删除会话本身
const sessionList = await baseDB.db.queryByField(tableName.value, 'sessionId', sessionId);
for (const session of sessionList) {
if (session.id) {
await baseDB.db.delete(tableName.value, session.id);
}
}
// 重新获取所有会话并重新分组
const allSessions = await baseDB.db.getAll(tableName.value);
if (allSessions.length) {
const [result, lastData] = insertSortData(allSessions);
tabeList.value = result;
} else {
tabeList.value = [];
}
// 如果删除的是当前会话,切换到第一个会话或清空
if (chatSessionID.value === sessionId) {
if (tabeList.value.length > 0) {
// 找到第一个非标题的会话
const firstSession = tabeList.value.find(item => !item.isTitle);
if (firstSession) {
chatSessionID.value = firstSession.sessionId;
await initMessage(firstSession.sessionId);
} else {
// 没有会话了
chatSessionID.value = '';
messages.value = [];
}
} else {
// 没有会话了
chatSessionID.value = '';
messages.value = [];
}
}
}
return {
messages,
isTyping,
textInput,
chatSessionID,
tabeList,
init,
toggleTyping,
addTabel,
addNewDialogue,
changeDialogue,
getStearm,
getHistory,
badFeedback,
deleteMessages,
deleteDialogue
};
});
function safeParseJSON(data) {
try {
return JSON.parse(data);
} catch {
return null; // 解析失败,返回 null
}
}
export default useChatGroupDBStore