diff --git a/.commitlintrc.cjs b/.commitlintrc.cjs index 28f82a0..9bb2aef 100644 --- a/.commitlintrc.cjs +++ b/.commitlintrc.cjs @@ -22,46 +22,33 @@ module.exports = { ignores: [(commit) => commit.includes('init')], extends: ['@commitlint/config-conventional'], rules: { - // 'body-leading-blank': [2, 'always'], - // 'footer-leading-blank': [1, 'always'], - // 'header-max-length': [2, 'always', 108], - // 'subject-empty': [2, 'never'], - // 'type-empty': [2, 'never'], - // 'subject-case': [0], - // 'type-enum': [ - // 2, - // 'always', - // [ - // 'feat', - // 'fix', - // 'perf', - // 'style', - // 'docs', - // 'test', - // 'refactor', - // 'build', - // 'ci', - // 'chore', - // 'revert', - // 'wip', - // 'workflow', - // 'types', - // 'release', - // ], - // ], + 'body-leading-blank': [2, 'always'], + 'footer-leading-blank': [1, 'always'], + 'header-max-length': [2, 'always', 108], + 'subject-empty': [2, 'never'], + 'type-empty': [2, 'never'], + 'subject-case': [0], 'type-enum': [ 2, 'always', - ['upd', 'feat', 'fix', 'refactor', 'docs', 'chore', 'style', 'revert'], + [ + 'feat', + 'fix', + 'perf', + 'style', + 'docs', + 'test', + 'refactor', + 'build', + 'ci', + 'chore', + 'revert', + 'wip', + 'workflow', + 'types', + 'release', + ], ], - 'type-case': [0], - 'type-empty': [0], - 'scope-empty': [0], - 'scope-case': [0], - 'subject-full-stop': [0], - 'subject-empty': [0], - 'subject-case': [0], - 'header-max-length': [0], }, prompt: { /** @use `pnpm commit :f` */ diff --git a/package.json b/package.json index d63bd29..4839db4 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ }, "lint-staged": { "*.{js,jsx,ts,tsx}": [ - "prettier --write" + "prettier --write", + "eslint --fix" ], "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [ "prettier --write--parser json" @@ -49,6 +50,7 @@ ], "*.vue": [ "prettier --write", + "eslint --fix", "stylelint --fix" ], "*.{scss,less,styl,html}": [ @@ -137,16 +139,17 @@ "@vben/vite-config": "workspace:*", "@vue/compiler-sfc": "3.4.37", "@vue/test-utils": "2.4.5", + "@microsoft/fetch-event-source":"2.0.1", "conventional-changelog-cli": "4.1.0", "cross-env": "7.0.3", "cz-git": "1.9.1", "czg": "1.9.1", - "emoji-picker-element": "1.12.1", "husky": "9.0.11", "lint-staged": "15.2.2", "micromark": "^3.1.0", "micromark-extension-gfm": "^2.0.1", "prettier": "3.3.3", + "emoji-picker-element": "1.12.1", "prettier-plugin-packagejson": "2.5.0", "rimraf": "5.0.5", "sass": "1.77.6", diff --git a/src/locales/setupI18n.ts b/src/locales/setupI18n.ts index ae6d71e..be26b3d 100644 --- a/src/locales/setupI18n.ts +++ b/src/locales/setupI18n.ts @@ -13,7 +13,8 @@ export let i18n: ReturnType; async function createI18nOptions(): Promise { const localeStore = useLocaleStoreWithOut(); const locale = localeStore.getLocale; - const defaultLocal = await import(`./lang/${locale}`); + const defaultLocal = await import(`./lang/${locale}.ts`); + // const defaultLocal = await import(localeModuleMap[locale]); const message = defaultLocal.default?.message ?? {}; setHtmlPageLang(locale); diff --git a/src/views/chat/index.vue b/src/views/chat/index.vue index d818426..57a652a 100644 --- a/src/views/chat/index.vue +++ b/src/views/chat/index.vue @@ -31,6 +31,12 @@ import { ContentTypeEnum } from '@/enums/httpEnum'; import { buildUUID } from '@/utils/uuid'; import { cloneDeep } from 'lodash-es'; + import { getToken } from '@/utils/auth'; + + import { fetchEventSource } from '@microsoft/fetch-event-source'; + import { useGlobSetting } from '@/hooks/setting'; + import { mapState } from 'pinia'; + // import { register } from './lib/index.js' // import { register } from 'vue-advanced-chat' @@ -45,6 +51,7 @@ { name: 'underline', title: '地名检查' }, { name: 'bold', title: '文档公司名识别' }, { name: 'color', title: '文档相似性检查' }, + { name: 'comment1', title: '文档结构检查' }, { name: 'comment', title: '文档图文分析' }, ]; @@ -100,6 +107,7 @@ const currentMsgSeq = ref(1); const roomMessage = ref(''); let roomIdCounter = 1; + const fileInfo = ref(); const rooms = ref([ { roomId: '1', //房间id(类似聊天对象id) @@ -298,10 +306,13 @@ disableActions: false, disableReactions: false, }; - + fileInfo.value = null; if (files) { message['files'] = formattedFiles(files); console.log(files); + fileInfo.value = new File([files[0].blob], files[0].name + '.' + files[0].extension, { + type: files[0].blob.type, + }); } if (replyMessage) { @@ -315,55 +326,26 @@ message['replyMessage'].files = replyMessage.files; } } - const file = new File([files[0].blob], files[0].name + '.' + files[0].extension, { - type: files[0].blob.type, - }); + const data = { - file: file, + // file: file, content: content, }; roomMsgMap[roomId].push(message); - roomMessages.value = [...roomMsgMap[roomId]] as any; - const qingshaodeng = { - _id: currentMsgSeq.value.toString(), - senderId: '2', - username: users['ai'].username, - avatar: users['ai'].avatar, - content: '请稍等', - timestamp: formatDate(new Date()), - date: formatDate(new Date()), - system: false, - saved: true, - distributed: true, - seen: true, - deleted: false, - failure: false, - disableActions: false, - disableReactions: false, - }; - roomMsgMap[roomId].push(qingshaodeng); roomMessages.value = [...roomMsgMap[roomId]] as any; - let getcontent = await defHttp.post({ - url: '/productManagement/supplierInformation/importData', - data, - headers: { - 'Content-Type': ContentTypeEnum.FORM_DATA, - }, - timeout: 4 * 60 * 1000, - }); + let getcontent = ref('文件上传中.....'); messagesLoaded.value = false; - // roomMsgMap[roomId].push(message); - // console.log(roomMsgMap[roomId]); + let nowDate = new Date(); const message1 = { _id: currentMsgSeq.value.toString(), senderId: '2', username: users['ai'].username, avatar: users['ai'].avatar, - content: getcontent, - timestamp: formatDate(new Date()), - date: formatDate(new Date()), + content: getcontent.value, + timestamp: formatDate(nowDate), + date: formatDate(nowDate), system: false, saved: true, distributed: true, @@ -380,6 +362,279 @@ //this.roomMessages = roomMsgMap[roomId] // console.log(this.roomMessages); messagesLoaded.value = true; + const { apiUrl, clientId } = useGlobSetting(); + const ctrl = new AbortController(); + const EventStreamContentType = 'text/event-stream; charset=utf-8'; + let formData = new FormData(); + formData.append('fileInfo', fileInfo.value); + formData.append('content', content); + //${apiUrl}/productManagement/supplierInformation/sse-invoke + let url = `${apiUrl}/productManagement/supplierInformation/sse-invoke`; + if (content.indexOf('地名检查') >= 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkPlaceName`; + } else if (content.indexOf('文档公司名识别') >= 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkCompanyName`; + } else if (content.indexOf('文档相似性检查') >= 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkRepeatText`; + } else if (content.indexOf('文档纠错') >= 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentError`; + } else if (content.indexOf('文档结构检查') >= 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkTitleName`; + } else if (content.indexOf('全功能文档分析') >= 0) { + url = `${apiUrl}/sse/checkDocumentAll`; + let uuid = buildUUID(); + formData.append('uuid', uuid + '.' + files[0].extension); + try { + await defHttp.post({ + url: '/productManagement/supplierInformation/upload', + data: formData, + headers: { + 'Content-Type': ContentTypeEnum.FORM_DATA, + }, + timeout: 10 * 60 * 1000, + }); + // 请求成功,处理响应 + // 可以在这里对 fileRes 进行进一步处理,如显示成功消息等 + } catch (error) { + // 请求失败,处理错误 + console.error('请求失败:', error); + // 根据需要显示错误消息或进行其他处理 + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: '**文件上传失败,请联系管理员**', + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1; + roomMessages.value = [...roomMsgMap[roomId]] as any; + return; + } + + const fetchPromises = []; + for (let i = 0; i < 5; i++) { + if (i >= 1) { + let getcontent = ref('请稍等...'); + messagesLoaded.value = false; + let nowDate = new Date(); + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: getcontent.value, + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId].push(message1); + roomMessages.value = [...roomMsgMap[roomId]] as any; + } + + let url; + if (i === 0) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkPlaceName`; + } else if (i === 1) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkCompanyName`; + } else if (i === 2) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkDocumentError`; + } else if (i === 3) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkTitleName`; + } else if (i === 4) { + url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkRepeatText`; + } + + // 将fetchEventSource封装为一个Promise + const fetchPromise = new Promise((resolve, reject) => { + setTimeout(() => { + fetchEventSource(url, { + method: 'POST', + headers: { + // 'Content-Type': 'application/json;charset=utf-8',//multipart/form-data;charset=UTF-8//application/json;charset=utf-8 + Authorization: `Bearer ${getToken()}`, + clientId: clientId, + }, + signal: ctrl.signal, + openWhenHidden: true, + body: formData, + async onmessage(msg: { data: string; event: string }) { + // ev.data里面是实时传递过来的数据 + // 根据后端返回的数据,我这里需要将字符串转成对象 + // let obj = JSON.parse(msg.data); + // // 拿到具体的内容 + + // getcontent.value +=msg.data.substring(getcontent.value.length); + getcontent.value = msg.data.replace('
', '\n'); + + console.log(getcontent.value); + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: getcontent.value, + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId][roomMsgMap[roomId].length - (5 - i)] = message1; + + roomMessages.value = [...roomMsgMap[roomId]] as any; + // Unicode转成中文 + }, + //会话发送完毕时触发 + onclose() { + //这里可以写结束时,你需要做的事,如果没有,可以删除 + }, + onerror(err) { + console.log('onerror', err); + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: '**出现异常,请联系管理员**', + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId][roomMsgMap[roomId].length - (5 - i)] = message1; + + roomMessages.value = [...roomMsgMap[roomId]] as any; + ctrl.abort(); + throw err; + }, + }); + }, 1500); + }); + + fetchPromises.push(fetchPromise); // 将Promise添加到数组 + } + + // 使用Promise.all并发执行所有请求 + Promise.all(fetchPromises) + .then(() => { + console.log('所有请求成功完成'); + }) + .catch((err) => { + console.error('处理过程中发生错误:', err); + }); + return; + } else if (content.indexOf('文档图文分析') >= 0) { + url = `${apiUrl}/sse/checkDocumentGraphic`; + } + await fetchEventSource(url, { + method: 'POST', + headers: { + // 'Content-Type': 'application/json;charset=utf-8',//multipart/form-data;charset=UTF-8//application/json;charset=utf-8 + Authorization: `Bearer ${getToken()}`, + clientId: clientId, + }, + signal: ctrl.signal, + openWhenHidden: true, + body: formData, + async onmessage(msg: { data: string; event: string }) { + // ev.data里面是实时传递过来的数据 + // 根据后端返回的数据,我这里需要将字符串转成对象 + // let obj = JSON.parse(msg.data); + // // 拿到具体的内容 + + // getcontent.value +=msg.data.substring(getcontent.value.length); + getcontent.value = msg.data.replaceAll('
', '\n'); + + console.log(getcontent.value); + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: getcontent.value, + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1; + + roomMessages.value = [...roomMsgMap[roomId]] as any; + // Unicode转成中文 + }, + //会话发送完毕时触发 + onclose() { + //这里可以写结束时,你需要做的事,如果没有,可以删除 + }, + onerror(err) { + console.log('onerror', err); + const message1 = { + _id: currentMsgSeq.value.toString(), + senderId: '2', + username: users['ai'].username, + avatar: users['ai'].avatar, + content: '**出现异常,请联系管理员**', + timestamp: formatDate(nowDate), + date: formatDate(nowDate), + system: false, + saved: true, + distributed: true, + seen: true, + deleted: false, + failure: false, + disableActions: false, + disableReactions: false, + }; + roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1; + + roomMessages.value = [...roomMsgMap[roomId]] as any; + ctrl.abort(); + throw err; + }, + }); + + // let getcontent = await defHttp.get({ + // url: '/productManagement/supplierInformation/sse-invoke', + // data, + // // headers: { + // // 'Content-Type': ContentTypeEnum.FORM_DATA, + // // }, + // timeout: 4 * 60 * 1000, + // }); } function formattedFiles(files) {