feat: 图表对接

main
许宏杰 2 months ago
parent 66b0a45740
commit 34f23c6d5a

@ -3,4 +3,4 @@ import { BarCrossrangeConfig } from './BarCrossrange/index'
import { CapsuleChartConfig } from './CapsuleChart/index' import { CapsuleChartConfig } from './CapsuleChart/index'
import { BarLineConfig } from './BarLine/index' import { BarLineConfig } from './BarLine/index'
export default [BarCommonConfig, BarCrossrangeConfig, BarLineConfig, CapsuleChartConfig] export default [BarCommonConfig, BarCrossrangeConfig, ]//BarLineConfigCapsuleChartConfig

@ -3,4 +3,4 @@ import { LineLinearSingleConfig } from './LineLinearSingle/index'
import { LineGradientSingleConfig } from './LineGradientSingle/index' import { LineGradientSingleConfig } from './LineGradientSingle/index'
import { LineGradientsConfig } from './LineGradients/index' import { LineGradientsConfig } from './LineGradients/index'
export default [LineCommonConfig, LineLinearSingleConfig, LineGradientSingleConfig, LineGradientsConfig] export default [LineCommonConfig, LineLinearSingleConfig]//LineGradientSingleConfig,LineGradientsConfig

@ -102,7 +102,7 @@ const styleColor: string[] = ['简约风', '商务风', '科技风']
const handleSend = async () => { const handleSend = async () => {
if (!keyWord.value.trim()) { if (!keyWord.value.trim()) {
messageDialog.warning('请先输入您想知道的问题') messageDialog.warning('请先输入需要统计的数据')
return return
} }

@ -7,6 +7,21 @@
height: chatRoom + 'px' height: chatRoom + 'px'
}" }"
> >
<div
:class="['chat-item', 'ai-message']"
>
<!-- 头像 -->
<img :src="aiIcon" class="user-icon" alt="" />
<!-- 内容 -->
<div class="message-content">
<div class="message-time">当前数据</div>
<div class="message-text">
<span>{{ toString(source)}}</span>
</div>
</div>
</div>
<div <div
v-for="(item, index) in messagesList" v-for="(item, index) in messagesList"
:key="index" :key="index"
@ -44,9 +59,13 @@
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
import { toString, isArray } from '@/utils'
import { ChartFrameEnum } from '@/packages/index.d'
import { useMessage } from 'naive-ui' import { useMessage } from 'naive-ui'
import { ref, reactive, watch, nextTick, onMounted } from 'vue' import { ref, reactive, watch, nextTick, onMounted ,computed} from 'vue'
import { DataResultEnum, TimelineTitleEnum } from '../../index.d'
import { useTargetData } from '../../../hooks/useTargetData.hook' import { useTargetData } from '../../../hooks/useTargetData.hook'
import moment from 'moment' import moment from 'moment'
// @ts-ignore // @ts-ignore
@ -57,14 +76,42 @@ import aiIcon from '@/assets/images/ai/ai-icon.png'
// //
const { targetData, chartEditStore } = useTargetData() const { targetData, chartEditStore } = useTargetData()
const source = ref()
let keyWord = ref('') let keyWord = ref('')
let loading = ref(false) let loading = ref(false)
const messageDialog = useMessage() const messageDialog = useMessage()
let messagesList = reactive([]) let messagesList :any[] = reactive([])
const scrollContainer = ref(null) const scrollContainer = ref<HTMLDivElement | null>(null)
const chatBxo = ref(null) const chatBxo =ref<HTMLDivElement | null>(null)
const chatInput = ref(null) const chatInput = ref<HTMLDivElement | null>(null)
let chatRoom = ref(0) let chatRoom = ref(0)
const noData = ref(false)
const dimensions = ref()
const dimensionsAndSource = ref()
// , mapping
const fieldList = ref<
Array<{
field: string
mapping: string[]
result: DataResultEnum
}>
>([])
//
const matchingHandle = (mapping: string) => {
let res = DataResultEnum.SUCCESS
for (let i = 0; i < source.value.length; i++) {
if (source.value[i][mapping] === undefined) {
res = DataResultEnum.FAILURE
return res
}
}
return DataResultEnum.SUCCESS
}
// //
const handleSend = async () => { const handleSend = async () => {
if (!keyWord.value.trim()) { if (!keyWord.value.trim()) {
@ -74,38 +121,38 @@ const handleSend = async () => {
/** /**
*保存用户提问信息 *保存用户提问信息
*/ */
messagesList.push({ const messagesItem = {
from: 'user', from: 'user',
text: keyWord.value, text: keyWord.value,
time: moment().format('YYYY/MM/DD HH:mm:ss') time: moment().format('YYYY/MM/DD HH:mm:ss')
}) }
messagesList.push(messagesItem)
loading.value = true loading.value = true
try { try {
const res = await getAiMsg({ prompt: keyWord.value }) const res = await getAiMsg({ prompt: keyWord.value })
let result = {} let result:any = {}
if(res.chartType){ if (res.chartType) {
result.dimensions = [ result.dimensions = ['product', 'data1']
'product','data1'
]
result.source = [] result.source = []
res.xData.map((item,index)=>{ res.xData.map((item:any, index:any) => {
result.source.push({ result.source.push({
product:item, product: item,
data1:parseInt(res.yData[index]) data1: parseInt(res.yData[index])
}) })
}) })
targetData.value.option.dataset = result
}else{ // targetData.value.option.messages = messagesItem
} else {
result = res result = res
} }
// //AI
//AI // messagesList.push({
messagesList.push({ // from: 'ai',
from: 'ai', // text: result,
text: result, // time: moment().format('YYYY/MM/DD HH:mm:ss')
time: moment().format('YYYY/MM/DD HH:mm:ss') // })
})
targetData.value.option.dataset = result
keyWord.value = '' // keyWord.value = '' //
loading.value = false loading.value = false
} catch (error) { } catch (error) {
@ -119,7 +166,56 @@ const handleSend = async () => {
loading.value = false loading.value = false
} }
} }
//
const dimensionsAndSourceHandle = () => {
try {
//
return dimensions.value.map((dimensionsItem: string, index: number) => {
return index === 0
? {
//
field: '通用标识',
//
mapping: dimensionsItem,
//
result: DataResultEnum.NULL
}
: {
field: `数据项-${index}`,
mapping: dimensionsItem,
result: matchingHandle(dimensionsItem)
}
})
} catch (error) {
return []
}
}
// dataset
const isCharts = computed(() => {
return targetData.value.chartConfig.chartFrame === ChartFrameEnum.ECHARTS
})
// vchart
const initFieldListHandle = () => {
if (targetData.value?.option) {
fieldList.value = []
// Field key
for (const key in targetData.value.option) {
if (key.endsWith('Field')) {
const value = targetData.value.option[key]
targetData.value.option[key] = value
const item = {
field: key,
mapping: value,
result: DataResultEnum.SUCCESS
}
if (item.mapping === undefined) {
item.result = DataResultEnum.FAILURE
}
fieldList.value.push(item)
}
}
}
}
//watch //watch
// messages // messages
watch( watch(
@ -134,11 +230,59 @@ watch(
{ deep: true } { deep: true }
) )
//
// watch(
// () => targetData.value.id,
// (
// ) => {
// messagesList = []
// },
// )
//
watch(
() => targetData.value?.option?.dataset,
(
newData?: {
source: any
dimensions: any
} | null
) => {
// console.log(targetData.value.option.messages,'sss')
noData.value = false
if (newData && targetData?.value?.chartConfig?.chartFrame === ChartFrameEnum.ECHARTS) {
// DataSet
source.value = newData
if (isCharts.value) {
dimensions.value = newData.dimensions
dimensionsAndSource.value = dimensionsAndSourceHandle()
}
} else if (newData && targetData?.value?.chartConfig?.chartFrame === ChartFrameEnum.VCHART) {
source.value = newData
initFieldListHandle()
} else if (newData !== undefined && newData !== null) {
dimensionsAndSource.value = null
source.value = newData
fieldList.value = []
} else {
noData.value = true
source.value = '此组件无数据源'
}
if (isArray(newData)) {
dimensionsAndSource.value = null
}
},
{
immediate: true
}
)
onMounted(() => { onMounted(() => {
if (chatBxo.value) { if (chatBxo.value && chatInput.value) {
// 使 offsetHeight // 使 offsetHeight
chatRoom.value = chatBxo.value.offsetHeight - (chatInput.value.offsetHeight+100 ) chatRoom.value = chatBxo.value.offsetHeight - (chatInput.value.offsetHeight + 100)
console.log(chatBxo.value.offsetHeight, '高度')
} }
}) })
</script> </script>
@ -161,6 +305,7 @@ onMounted(() => {
gap: 25px; gap: 25px;
width: 100%; width: 100%;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden;
.chat-item { .chat-item {
display: flex; display: flex;
gap: 6px; gap: 6px;

@ -7,7 +7,7 @@
<!-- 位置 --> <!-- 位置 -->
<position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig" /> <position-setting :chartAttr="targetData.attr" :canvasConfig="chartEditStore.getEditCanvasConfig" />
<!-- 滤镜 --> <!-- 滤镜 -->
<styles-setting :isGroup="targetData.isGroup" :chartStyles="targetData.styles"></styles-setting> <!-- <styles-setting :isGroup="targetData.isGroup" :chartStyles="targetData.styles"></styles-setting> -->
<!-- 自定义配置项 --> <!-- 自定义配置项 -->
<component :is="targetData.chartConfig.conKey" :optionData="targetData.option"></component> <component :is="targetData.chartConfig.conKey" :optionData="targetData.option"></component>
</div> </div>

@ -8,6 +8,7 @@ export const useTargetData = () => {
const targetData: Ref<CreateComponentType | CreateComponentGroupType> = computed(() => { const targetData: Ref<CreateComponentType | CreateComponentGroupType> = computed(() => {
const list = chartEditStore.getComponentList const list = chartEditStore.getComponentList
const targetIndex = chartEditStore.fetchTargetIndex() const targetIndex = chartEditStore.fetchTargetIndex()
return list[targetIndex] return list[targetIndex]
}) })
return { targetData, chartEditStore } return { targetData, chartEditStore }

@ -134,16 +134,16 @@ const chartsDefaultTabList = [
icon: ConstructIcon, icon: ConstructIcon,
render: ChartSetting render: ChartSetting
}, },
{ // {
key: TabsEnum.CHART_ANIMATION, // key: TabsEnum.CHART_ANIMATION,
title: '动画', // title: '',
icon: LeafIcon, // icon: LeafIcon,
render: ChartAnimation // render: ChartAnimation
} // }
] ]
const chartsTabList = [ const chartsTabList = [
// ...chartsDefaultTabList, ...chartsDefaultTabList,
{ {
key: TabsEnum.CHART_DATA, key: TabsEnum.CHART_DATA,
title: '统计数据', title: '统计数据',
@ -171,7 +171,7 @@ const chartsTabList = [
} }
::v-deep .n-scrollbar-content{ ::v-deep .n-scrollbar-content{
height: 100%; height: 100%;
overflow: hidden;
} }
.n-tabs{ .n-tabs{
height: 100%; height: 100%;

Loading…
Cancel
Save