feat: 聊天室历史记录对接

main
许宏杰 1 month ago
parent b01f61b773
commit f2ddf37d69

@ -113,6 +113,7 @@ export const translateStr = (target: string | Record<any, any>) => {
* @param globalParams
*/
export const customizeHttp = (targetParams: RequestConfigType, globalParams: RequestGlobalConfigType) => {
if (!targetParams || !globalParams) {
return
}

@ -26,6 +26,15 @@ export const historyMessageRoom = async(data: object)=>{
}
}
export const historyMessageRoomUpdata = async(data: object)=>{
try{
const res = await http(RequestHttpEnum.PUT)(`${ModuleTypeEnum.MESSAGE}`, data)
return res
}catch{
httpErrorHandle()
}
}
export const historyMessageRoomList = async(data?: object)=>{
try{
const res = await http(RequestHttpEnum.GET)(`${ModuleTypeEnum.MESSAGE}`, data)

@ -73,6 +73,7 @@ export const useChartDataFetch = (
clearInterval(fetchInterval)
const fetchFn = async () => {
const res = await customizeHttp(toRaw(targetComponent.request), toRaw(chartEditStore.getRequestGlobalConfig))
if (res) {
try {

@ -20,9 +20,9 @@ import cloneDeep from 'lodash/cloneDeep'
// 请求基础属性
export const requestConfig: RequestConfigType = {
requestDataType: RequestDataTypeEnum.STATIC,
requestHttpType: RequestHttpEnum.GET,
requestUrl: '',
requestDataType: RequestDataTypeEnum.AJAX,
requestHttpType: RequestHttpEnum.POST,
requestUrl: 'http://baijiahu.mynatapp.cc/',
requestInterval: undefined,
requestIntervalUnit: RequestHttpIntervalEnum.SECOND,
requestContentType: RequestContentTypeEnum.DEFAULT,

@ -2,15 +2,15 @@ import { defineStore } from 'pinia'
const useMessageRoomStore = defineStore('useMessageRoomStore', {
state: () => ({
messageRoom: {
fristIssue:undefined,
list:[]
id:undefined,
createUserId:undefined,
content:[]
}
}),
actions: {
setMessage(fristIssue,item) {
if (this.messageRoom.list.length >= 35) return
if(!this.messageRoom.fristIssue) this.messageRoom.fristIssue = fristIssue
this.messageRoom.list.push(item)
setMessage(item) {
if (this.messageRoom.content.length >= 35) return
this.messageRoom.content.push(item)
},
resetList(obj){
this.messageRoom = obj

@ -69,9 +69,21 @@
align-items: flex-start;
}
.ai-hint {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 6px;
font-size: 12px;
color: #c3cad9;
gap: 10px;
.upload-text{
cursor: pointer;
display: flex;
align-items: center;
}
.upload-text:hover{
color: #3F7BF8;
}
}
}
.message-content {

@ -181,5 +181,6 @@ export class BarChart {
this.chart.dispose()
this.chart = null
}
console.log('清除',this.chart)
}
}

@ -25,7 +25,7 @@
<!-- 内容 -->
<div class="message-content">
<div class="message-time">{{ item.time }}</div>
<div class="message-text">
<div class="message-text" :id="`box${index}`">
<!-- 纯文本 -->
<div class="text-ros">
<span>{{ item.text }}</span>
@ -76,7 +76,24 @@
</div>
<!-- 免责 -->
<div class="ai-hint" v-show="item.from === 'ai' && (item.text || item.chartType)">
本回答由AI生成内容仅供参考
<span>本回答由AI生成内容仅供参考</span>
<div class="upload-text" @click="uploadImage(index)">
<n-icon size="14">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 16 16"
>
<g fill="none">
<path
d="M3.5 13h9a.75.75 0 0 1 .102 1.493l-.102.007h-9a.75.75 0 0 1-.102-1.493L3.5 13h9h-9zM7.898 1.007L8 1a.75.75 0 0 1 .743.648l.007.102v7.688l2.255-2.254a.75.75 0 0 1 .977-.072l.084.072a.75.75 0 0 1 .072.977l-.072.084L8.53 11.78a.75.75 0 0 1-.976.073l-.084-.073l-3.536-3.535a.75.75 0 0 1 .977-1.133l.084.072L7.25 9.44V1.75a.75.75 0 0 1 .648-.743L8 1l-.102.007z"
fill="currentColor"
></path>
</g>
</svg>
</n-icon>
<span>下载图片</span>
</div>
</div>
</div>
</div>
@ -110,6 +127,15 @@ import { LineChart, BarChart, PieChart } from './class/index'
import { AiHint } from '../components'
import userIcon from '@/assets/images/ai/user-icon.png'
import aiIcon from '@/assets/images/ai/ai-icon.png'
import { useMessage } from 'naive-ui'
import useMessageRoomStore from '@/store/modules/messageRoom'
import { canvasCut } from '@/utils'
import { historyMessageRoomById } from '@/api/path'
import { useRoute } from 'vue-router'
const route = useRoute()
const useMessageRoom = useMessageRoomStore()
const messageDialog = useMessage()
//
let loading = ref(false)
//
@ -128,25 +154,55 @@ let stopWatch = null
* 页面初始完成
*/
onMounted(() => {
// bar = new PieChart('barEcharts', {
// title:'',
// unit:'',
// data: [
// { value: 1048, name: 'Search Engine' },
// { value: 735, name: 'Direct' },
// { value: 580, name: 'Email' },
// { value: 484, name: 'Union Ads' },
// { value: 300, name: 'Video Ads' },
// { value: 200, name: 'qq Ads' },
// { value: 100, name: 'vx Ads' }
// ]
// })
startWatching()
getMessageInfo()
})
/**
* 获取聊天详情
*/
const getMessageInfo = async () => {
const id = checkLastPartIsTimestamp(route.path)
try {
const res = await historyMessageRoomById(id)
if (res.code == 200 && res.data) {
res.data.content = JSON.parse(res.data.content)
useMessageRoom.resetList(res.data)
res.data.content.map((item, index) => {
messageList.push(item)
initEcharts(item, index)
})
console.log(res.data)
}
} catch {
messageDialog.error('获取聊天室记录失败!')
}
}
const checkLastPartIsTimestamp = str => {
// /
const lastSlashIndex = str.lastIndexOf('/')
if (lastSlashIndex === -1) {
return false
}
// /
const lastPart = str.slice(lastSlashIndex + 1)
return lastPart
}
/**
* 问答
*/
const handleSend = async () => {
if (!keyWord.value.trim()) {
messageDialog.warning('请先输入需要统计的数据!')
return
}
if (useMessageRoom.messageRoom.content.length >= 35) {
messageDialog.warning('每个聊天室上限问题为15条')
return
}
loading.value = true
//
setMessageItem({
@ -156,17 +212,20 @@ const handleSend = async () => {
add: true
})
//AI
setMessageItem({
from: 'ai',
text: '',
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: true, //ai
chartInstanceItem: null,
chartInstanceActiveIndex: 0,
chartType: null,
xData: [],
yData: []
})
setMessageItem(
{
from: 'ai',
text: '',
time: moment().format('YYYY/MM/DD HH:mm:ss'),
loading: true, //ai
chartInstanceItem: null,
chartInstanceActiveIndex: 0,
chartType: null,
xData: [],
yData: []
},
false
)
try {
const res = await getAiMsg({ prompt: keyWord.value })
if (res.type) {
@ -184,6 +243,7 @@ const handleSend = async () => {
title: res.title,
unit: res.unit
})
nextTick(() => {
const itemData = messageList[lastIndex.value]
//
@ -228,14 +288,53 @@ const handleSend = async () => {
})
}
}
/**
* 同意渲染图表
*/
const initEcharts = (item, index) => {
nextTick(() => {
//
if (item.chartType === 'pie') {
item.chartInstanceItem = new PieChart(`${item.chartType}${index}`, {
title: item.title,
unit: item.unit,
xData: item.xData,
data: item.yData
})
} else if (item.chartType === 'bar') {
item.chartInstanceItem = new BarChart(`${item.chartType}${index}`, {
title: item.title,
unit: item.unit,
xData: item.xData,
data: item.yData
})
} else if (item.chartType === 'line') {
item.chartInstanceItem = new LineChart(`${item.chartType}${index}`, {
title: item.title,
unit: item.unit,
xData: item.xData,
data: item.yData
})
}
})
}
/**
* 存储聊天室数据
* @param obj
*/
const setMessageItem = obj => {
const setMessageItem = (obj, set = true) => {
messageList.push(obj)
lastIndex.value = messageList.length - 1
if (set) {
useMessageRoom.setMessage({
from: obj.from,
text: obj.text,
time: obj.time,
add: true
})
}
}
/**
@ -246,6 +345,19 @@ const updataMessageItem = data => {
messageList[lastIndex.value] = data
keyWord.value = ''
loading.value = false
useMessageRoom.setMessage({
from: data.from,
text: data.text,
chartType: data.chartType,
loading: false, //ai
time: data.time,
chartInstanceItem: data.chartInstanceItem,
chartInstanceActiveIndex: 0,
xData: data.xData,
yData: data.yData,
title: data.title,
unit: data.unit
})
}
/**
@ -256,10 +368,25 @@ const handlerTheme = (item, index) => {
pauseWatching()
item.chartInstanceActiveIndex = index
item.chartInstanceItem.changeColorStyle(index)
setTimeout(()=>{
setTimeout(() => {
startWatching()
},1000)
}, 1000)
}
/**
* 下载AI回答为图片
*/
const uploadImage = index => {
//
const range = document.getElementById(`box${index}`)
// 线
if (!range) {
window['$message'].error('下载失败!')
return
}
canvasCut(range)
}
//
@ -280,8 +407,14 @@ const pauseWatching = () => {
stopWatch = null
}
}
onMounted(() => {
startWatching()
onUnmounted(() => {
//
messageList.forEach(instance => {
if (instance.chartType) {
instance.chartInstanceItem.dispose()
}
})
})
</script>

@ -1,8 +0,0 @@
export interface AiChatroom {
from:string,//来自谁
time:string,//时间
test?:string,//纯文本
}
export type AiChatroomType = AiChatroom;

@ -1,35 +1,39 @@
<template>
<div class="history-box">
<div class="history-title">聊天历史记录</div>
<div class="history-list">
<div class="history-item" v-for="item in list" :key="item.id" @click="getMessageInfo(item.id)">
<div class="history-row-title">{{ formatFristIssue(item) }}</div>
<div class="history-row-icon" @click.stop="delMessageItem(item.id)">
<n-icon size="14" color="#F25D44" class="del-icon">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">
<path d="M12 12h2v12h-2z" fill="currentColor"></path>
<path d="M18 12h2v12h-2z" fill="currentColor"></path>
<path d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z" fill="currentColor"></path>
<path d="M12 2h8v2h-8z" fill="currentColor"></path>
</svg>
</n-icon>
<section v-show="list.length > 0">
<div class="history-title">聊天历史记录</div>
<div class="history-list">
<div class="history-item" v-for="item in list" :key="item.id" @click="getMessageInfo(item.id)">
<div class="history-row-title">{{ formatFristIssue(item) }}</div>
<div class="history-row-icon" @click.stop="delMessageItem(item.id)">
<n-icon size="14" color="#F25D44" class="del-icon">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">
<path d="M12 12h2v12h-2z" fill="currentColor"></path>
<path d="M18 12h2v12h-2z" fill="currentColor"></path>
<path d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z" fill="currentColor"></path>
<path d="M12 2h8v2h-8z" fill="currentColor"></path>
</svg>
</n-icon>
</div>
</div>
</div>
</div>
<div class="history-title">看板历史记录</div>
<div class="history-list">
<div class="history-item"></div>
</div>
</section>
<section v-show="boardLsit.length > 0">
<div class="history-title">看板历史记录</div>
<div class="history-list">
<div class="history-item"></div>
</div>
</section>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { projectListApi, deleteProjectApi, historyMessageRoomList,historyMessageRoomDel } from '@/api/path'
import { projectListApi, deleteProjectApi, historyMessageRoomList, historyMessageRoomDel } from '@/api/path'
import { useRouter } from 'vue-router'
let list = ref([])
let boardLsit = ref([])
const router = useRouter()
//List
const fetchList = async () => {
@ -43,7 +47,7 @@ const delProjectItem = async id => {
const formatFristIssue = value => {
const data = JSON.parse(value.content)
return data.fristIssue
return data[0].text
}
//list
const messageList = async () => {
@ -51,14 +55,11 @@ const messageList = async () => {
list.value = res.data.records
}
//
const delMessageItem = async (id) => {
const delMessageItem = async id => {
const res = await historyMessageRoomDel(id)
if(res){
if (res) {
messageList()
}
}
const getMessageInfo = id => {
@ -67,7 +68,7 @@ const getMessageInfo = id => {
onMounted(() => {
// fetchList()
// messageList()
messageList()
})
defineExpose({

@ -1,3 +1,3 @@
export { default as AiHint } from './aiHint/index.vue'
// export { default as history } from './history'
// export { default as logo } from './logo'
export { default as AiHistory } from './history/index.vue'
export { default as AiLogo } from './logo/index.vue'

@ -30,11 +30,11 @@
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { createProjectApi, historyMessageRoom } from '@/api/path'
import { createProjectApi, historyMessageRoom ,historyMessageRoomUpdata} from '@/api/path'
import { getUUID } from '@/utils'
import { ResultEnum } from '@/enums/httpEnum'
import AiLogo from '../AI/components/logo/index.vue'
import AiHistory from '../AI/components/history/index.vue'
import { AiLogo, AiHistory } from './components'
import { ref } from 'vue'
import useMessageRoomStore from '@/store/modules/messageRoom'
import { useSystemStore } from '@/store/modules/systemStore/systemStore'
@ -53,8 +53,43 @@ const menuList = [
const getCurrentRoute = path => {
return route.path.includes(path)
}
const handlerPath = async (path, index) => {
router.push(path + '/' + Date.now())
const saveMessage = async path => {
//
if (useMessageRoom.messageRoom.content.length > 0) {
useMessageRoom.messageRoom.content.forEach(instance => {
if (instance.chartType && instance.chartInstanceItem) {
instance.chartInstanceItem.dispose()
}
})
const jsonData = JSON.stringify(useMessageRoom.messageRoom.content)
let res
try {
if (useMessageRoom.messageRoom.id) {
res = await historyMessageRoomUpdata({ content: jsonData, createUserId: useMessageRoom.messageRoom.id })
} else {
res = await historyMessageRoom({ content: jsonData, createUserId: systemStore.userInfo.userId || 1 })
}
if (res && res.code == 200) {
useMessageRoom.resetList({ id: undefined, createUserId: undefined, content: [] }) //
history.value.messageList()
router.push(path + '/' + Date.now())
}
} catch {
console.log('保存出错')
router.push(path + '/' + Date.now())
}
} else {
router.push(path + '/' + Date.now())
}
}
const handlerPath = (path, index) => {
if (index === 0) {
saveMessage(path)
}
// if (index == 1) {
// if (history.value) {
// // history.value.fetchList()

@ -61,6 +61,7 @@
</setting-item>
</setting-item-box>
<div v-if="requestContentType === RequestContentTypeEnum.DEFAULT">
<n-tabs type="line" animated v-model:value="tabValue">
<n-tab v-for="item in RequestParamsTypeEnum" :key="item" :name="item" :tab="item"> {{ item }} </n-tab>
</n-tabs>

@ -12,6 +12,7 @@
</n-tabs>
<!-- 各个页面 -->
<div class="go-mt-3">
<div v-if="tabValue !== RequestParamsTypeEnum.BODY">
<request-header-table :target="requestParams[tabValue]" @update="updateRequestParams"></request-header-table>

@ -1,8 +1,8 @@
<template>
<div class="go-chart-configurations-data" v-if="targetData">
<!-- <setting-item-box name="请求方式" :alone="true">
<setting-item-box name="请求方式" :alone="true">
<n-select v-model:value="targetData.request.requestDataType" :disabled="isNotData" :options="selectOptions" />
</setting-item-box> -->
</setting-item-box>
<!-- 静态 -->
<chart-data-static v-if="targetData.request.requestDataType === RequestDataTypeEnum.STATIC"></chart-data-static>
<!-- 动态 -->

@ -134,28 +134,28 @@ const chartsDefaultTabList = [
icon: ConstructIcon,
render: ChartSetting
},
// {
// key: TabsEnum.CHART_ANIMATION,
// title: '',
// icon: LeafIcon,
// render: ChartAnimation
// }
{
key: TabsEnum.CHART_ANIMATION,
title: '动画',
icon: LeafIcon,
render: ChartAnimation
}
]
const chartsTabList = [
...chartsDefaultTabList,
{
key: TabsEnum.CHART_DATA,
title: '统计数据',
title: '数据',
icon: FlashIcon,
render: ChartData
},
// {
// key: TabsEnum.CHART_EVENT,
// title: '',
// icon: RocketIcon,
// render: ChartEvent
// }
{
key: TabsEnum.CHART_EVENT,
title: '事件',
icon: RocketIcon,
render: ChartEvent
}
]
</script>

@ -321,6 +321,7 @@ export const useMouseHandle = () => {
// * 进入事件
const mouseenterHandle = (e: MouseEvent, item: CreateComponentType | CreateComponentGroupType) => {
e.preventDefault()
e.stopPropagation()
if (!chartEditStore.getEditCanvas.isSelect) {

Loading…
Cancel
Save