/* 图表,表格,PPT生成的入口函数 */ //图表 function draw_chart(name,rsp,type){ var ctx = document.getElementById(name).getContext('2d'); const data = JSON.parse(rsp.data); var result={}; if (type=="do_group_count") { if (rsp.cols.length==2){ //普通柱状图 result=draw_chart_bar(ctx,data,rsp.cols); }else if(rsp.cols.length==3){ // 堆叠柱状图, result=draw_chart_bar_stack(ctx,data,rsp.cols); }else{ //三个及以上,使用一维方式表达 result=draw_chart_bar_on3(ctx,data,rsp.cols); } }//end if if (["do_group_agg","do_fields_agg"].includes(type)){ if(rsp.cols.length==7){ // 分组柱状图,一个维度,6个指标 result=draw_chart_bar_by_d6(ctx,data,rsp.cols,rsp.field); }else if(rsp.cols.length==8){ //分组堆积图,两个个维度,6个指标 result=draw_chart_bar_by_d6_2(ctx,data,rsp.cols,rsp.field); } }//end do_group_sum return result; }//end funciton draw_chart //表格 function draw_table(name,rsp,desc){ var div = document.getElementById(name) const data = JSON.parse(rsp.data); //console.info(data); var html=`

${rsp.desc}

` //表头 rsp.cols.forEach(function(item, index) { let th=``; html += th; }); html +="" //数据的遍历 data.forEach(function(row, index) { html +="" //行数据 rsp.cols.forEach(function(item, index) { let td=``; html += td; }); html += ""; }); html +="
${item}
${row[item]}
"; div.innerHTML=html; return html; } function getFormattedDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are zero based const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } //生成ppt,单独的文件,使用数据方式 function gen_ppt(file_name,req,rsp,chat_id){ const today = new Date(); var ppt=`

K3GPT数据分析智能体

${file_name}

制作日期: ${getFormattedDate(today)}

`; ppt += `

用户需求

${req}
`; var table_index=1; //分析过程 if (Object.keys(chart_datas[chat_id]).length != 0){ ppt += `

数据分析

`; let obj = chart_datas[chat_id]; for (let key in obj) { if (key.startsWith("Table_")){ ppt += `

表格${table_index++}

`; ppt += obj[key]; }else{ ppt += `

${key}

`; ppt += `

[chart][bar]

${obj[key]}
`; } } } //结论 ppt += `

小结

${rsp}`; return ppt; } //生成ppt,单独的文件,使用前端报表的图片 async function gen_ppt_by_img(file_name,req,rsp,chat_id){ const today = new Date(); var ppt=`

K3GPT数据分析智能体

${file_name}

制作日期: ${getFormattedDate(today)}

`; ppt += `

用户需求

${req}
`; var table_index=1; //分析过程 if (Object.keys(chart_datas[chat_id]).length != 0){ ppt += `

数据分析

`; let obj = chart_datas[chat_id]; for (let key in obj) { if (key.startsWith("Table_")){ ppt += `

表格${table_index++}

`; ppt += obj[key]; }else{ ppt += `

${key}

`; //postChartImageData(chart_ids[chat_id][key],key).then(ret =>{ var ret = await postChartImageData(chart_ids[chat_id][key],key); console.info(ret); if (ret.errno==0){ ppt += `

${ret.data.alt}

`; console.info(ppt); }else{ ppt += `

图表数据:${ret.message}

`; } //}); } } } //结论 ppt += `

小结

${rsp}`; return ppt; } //提交图表的图片数据 async function postChartImageData(name,title) { const url = '/api/img_base64'; const chartCanvas = document.getElementById(name); const imageBase64 = chartCanvas.toDataURL('image/png'); const data = { img_base64_data: imageBase64, alias: title }; const response = await axios.post(url, data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); return response.data; } //生成ppt,不带封面 function gen_ppt_slides(req,rsp,chat_id){ //暂时去掉用户需求,和引导页有些重复 //var ppt = `

用户需求

${req}
`; var ppt=""; var table_index=1; //分析过程 if (Object.keys(chart_datas[chat_id]).length != 0){ ppt += `

数据分析

`; let obj = chart_datas[chat_id]; for (let key in obj) { if (key.startsWith("Table_")){ ppt += `

表格${table_index++}

`; ppt += obj[key]; }else{ ppt += `

${key}

`; ppt += `

[chart][bar]

${obj[key]}
`; } } } //结论 ppt += `

小结

${rsp}`; return ppt; } // 扩展后的背景颜色组 let backgroundColor = [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)', // 新增的颜色 'rgba(255, 99, 71, 0.2)', // 番茄红 'rgba(144, 238, 144, 0.2)', // 淡绿 'rgba(173, 216, 230, 0.2)', // 浅天蓝 'rgba(255, 192, 203, 0.2)' // 浅粉 ]; // 扩展后的边框颜色组 let borderColor = [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)', // 新增的颜色 'rgba(255, 99, 71, 1)', // 番茄红 'rgba(144, 238, 144, 1)', // 淡绿 'rgba(173, 216, 230, 1)', // 浅天蓝 'rgba(255, 192, 203, 1)' // 浅粉 ]; //柱状图,一个维度,一个count function draw_chart_bar(ctx,data,cols){ var title = cols[0]+"分布"; var groups = data.map(item => item[cols[0]]); var values = data.map(item => item.count); var myChart = new Chart(ctx, { type: 'bar', data: { labels: groups, datasets: [{ data: values, backgroundColor: backgroundColor, borderColor:borderColor, borderWidth: 1 }] }, options: { plugins: { title: { display: true, text: title, position: 'top', // 可选:'top', 'left', 'bottom', 'right' font: { size: 16, family: 'Helvetica', weight: 'bold', color: '#333' } }, legend: { display: false, //不显示图例 position: 'top' } }, } }); return {"title":title,"data":JSON.stringify({"categories":groups,"count":values})} } //堆叠柱状图,两个维度,一个count function draw_chart_bar_stack(ctx,data,cols){ //使用一个map的结构,来分离不同的数据 var title = cols[0]+"->"+cols[1]+"的分布"; var city = cols[0]; //第一个字段名称 var area = cols[1]; //第二个字段名称 // 创建一个映射来存储结果 let resultMap = {}; data.forEach(item => { if (!resultMap[item[city]]) { resultMap[item[city]] = {}; // 初始化城市 } resultMap[item[city]][item[area]] = item.count; // 填充数据 }); //console.info(resultMap); // 准备Chart.js所需的datasets和labels let labels = []; let datasets = []; let index=0; // 获取所有不同的area名称 let areas = new Set(); for (let city in resultMap) { for (let area in resultMap[city]) { areas.add(area); } labels.push(city); // 添加城市作为标签 } areas.forEach(area => { let dataset = { label: area, data: [], stack: 'Stack 0', // 所有数据集属于同一堆栈 backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index], borderWidth: 1 }; labels.forEach(city => { dataset.data.push(resultMap[city][area] || 0); // 如果该城市没有对应区域的数据,则填充0 }); datasets.push(dataset); index ++; }); //console.info(labels); //console.info(datasets); //画图 var myChart = new Chart(ctx, { type: 'bar', // 或者 'line' 来创建堆叠折线图 data: { labels: labels, // X轴标签 datasets: datasets, }, options: { plugins: { title: { display: true, text: title, position: 'top', // 可选:'top', 'left', 'bottom', 'right' font: { size: 16, family: 'Helvetica', weight: 'bold', color: '#333' } }, legend: { display: true, labels: { // 自定义生成图例项 generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels(chart); // 只保留前6个图例项 return original.slice(0, 6); } } } }, scales: { x: { stacked: true // 设置X轴为堆叠(适用于柱状图) }, y: { stacked: true// 设置Y轴为堆叠 } } } }); // ppt 数据 var series={} datasets.forEach(item=>{ series[item.label] = item.data; }) series["categories"] = labels; return {"title":title,"data":JSON.stringify(series)} } function draw_chart_bar_on3(ctx,data,cols){ var groups = data.map(item => item[cols[0]]+'->'+item[cols[1]]+'->'+item[cols[2]]); var title = cols[0]+"->"+cols[1]+"->"+cols[2]+"等的分布分析"; var values = data.map(item => item.count); var myChart = new Chart(ctx, { type: 'bar', data: { labels: groups, datasets: [{ data: values, backgroundColor: backgroundColor, borderColor:borderColor, borderWidth: 1 }] }, options: { plugins: { title: { display: true, text: title, position: 'top', // 可选:'top', 'left', 'bottom', 'right' font: { size: 16, family: 'Helvetica', weight: 'bold', color: '#333' } }, legend: { display: false, //不显示图例 position: 'top' } }, } }); return {"title":title,"data":JSON.stringify({"categories":groups,"count":values})} } //分组柱状图,一个维度,6个指标 function draw_chart_bar_by_d6(ctx,data,cols,field){ //标题 var title = "不同"+cols[0]+"对应的"+field+"的常见六指标分析"; // 准备结果对象 let index=0; let result = { labels: [], datasets: [ {label: '总和', type:"line", data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-1'}, {label: '平均值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '中位数', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '最小值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '最大值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '个数', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, ] }; // 对原始数据按级别排序(可选),一个维度 data.sort((a, b) => a[cols[0]].localeCompare(b[cols[0]])); // 填充labels和datasets的数据 data.forEach(item => { result.labels.push(item[cols[0]]); result.datasets[0].data.push(item.total); result.datasets[1].data.push(item.avg); result.datasets[2].data.push(item.median); result.datasets[3].data.push(item.min); result.datasets[4].data.push(item.max); result.datasets[5].data.push(item.count); }); //画图 var myChart = new Chart(ctx, { type: 'bar', // 或者 'line' 来创建堆叠折线图 data: result, options: { plugins: { title: { display: true, text: title, position: 'top', // 可选:'top', 'left', 'bottom', 'right' font: { size: 16, family: 'Helvetica', weight: 'bold', color: '#333' } }, legend: { display: true, labels: { // 自定义生成图例项 generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels(chart); // 只保留前6个图例项 return original.slice(0, 6); } } } }, scales: { x: { stacked: false // 设置X轴为堆叠(适用于柱状图) }, // 左边 Y 轴(用于 Total) 'y-1': { type: 'linear', display: true, position: 'right', title: { display: true, text: '总量' }, grid: { drawOnChartArea: false // 是否绘制网格线 } }, // 右边 Y 轴(用于 Average、Count 等) 'y-2': { type: 'linear', display: true, position: 'left', title: { display: true, text: field, }, grid: { drawOnChartArea: true // 不在右侧画网格线 } }, } } }); // ppt 数据 var series={} series["categories"] = result.labels; series["总和"] = result.datasets[0].data; series["平均值"] = result.datasets[1].data; series["中位数"] = result.datasets[2].data; series["最小值"] = result.datasets[3].data; series["最大值"] = result.datasets[4].data; series["个数"] = result.datasets[5].data; return {"title":title,"data":JSON.stringify(series)} } //分组柱状图,两个维度,6个指标 function draw_chart_bar_by_d6_2(ctx,data,cols,field){ //标题 var title = cols[0]+"->"+cols[1]+"对应的"+field+"的常见六指标分析"; // 准备结果对象 let index=0; let result = { labels: [], datasets: [ {label: '总和', type:"line", data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-1'}, {label: '平均值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '中位数', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '最小值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '最大值', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, {label: '个数', data: [],backgroundColor: backgroundColor[index], // 可以为每个区域分配不同颜色 borderColor: borderColor[index++], borderWidth: 1,yAxisID: 'y-2',}, ] }; // 对原始数据按级别排序(可选),一个维度 data.sort((a, b) => a[cols[0]].localeCompare(b[cols[0]])); // 填充labels和datasets的数据 data.forEach(item => { result.labels.push(item[cols[0]]+"->"+item[cols[1]]); result.datasets[0].data.push(item.total); result.datasets[1].data.push(item.avg); result.datasets[2].data.push(item.median); result.datasets[3].data.push(item.min); result.datasets[4].data.push(item.max); result.datasets[5].data.push(item.count); }); //画图 var myChart = new Chart(ctx, { type: 'bar', // 或者 'line' 来创建堆叠折线图 data: result, options: { plugins: { title: { display: true, text: title, position: 'top', // 可选:'top', 'left', 'bottom', 'right' font: { size: 16, family: 'Helvetica', weight: 'bold', color: '#333' } }, legend: { display: true, labels: { // 自定义生成图例项 generateLabels: function(chart) { const original = Chart.defaults.plugins.legend.labels.generateLabels(chart); // 只保留前6个图例项 return original.slice(0, 6); } } } }, scales: { x: { stacked: false // 设置X轴为堆叠(适用于柱状图) }, // 左边 Y 轴(用于 Total) 'y-1': { type: 'linear', display: true, position: 'right', title: { display: true, text: '总量' }, grid: { drawOnChartArea: false // 是否绘制网格线 } }, // 右边 Y 轴(用于 Average、Count 等) 'y-2': { type: 'linear', display: true, position: 'left', title: { display: true, text: field, }, grid: { drawOnChartArea: true // 不在右侧画网格线 } }, } } }); // ppt 数据 // ppt 数据 var series={} series["categories"] = result.labels; series["总和"] = result.datasets[0].data; series["平均值"] = result.datasets[1].data; series["中位数"] = result.datasets[2].data; series["最小值"] = result.datasets[3].data; series["最大值"] = result.datasets[4].data; series["个数"] = result.datasets[5].data; return {"title":title,"data":JSON.stringify(series)} }