6 changed files with 838 additions and 1 deletions
@ -0,0 +1,65 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import axios from 'axios'; |
||||
|
/** |
||||
|
* 获取设备生命周期系统的设备档案树 |
||||
|
*/ |
||||
|
export function getDevicesTree() { |
||||
|
return request({ |
||||
|
url: "/aibot/devices/tree", |
||||
|
method: "get", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
export function getDevicesMonitors(data:{deviceCode:string,rows:number,page:number}) { |
||||
|
return axios.post( import.meta.env.VITE_APP_BASE_API+"/aibot/devices/ep_monitors",data); |
||||
|
} |
||||
|
|
||||
|
// 获取ChatBI列表
|
||||
|
export function getChatBIList() { |
||||
|
return request({ |
||||
|
url: '/aibot/chatbi/list', |
||||
|
method: 'get', |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 创建ChatBI
|
||||
|
export function newChatBI(data: any) { |
||||
|
return request({ |
||||
|
url: '/aibot/chatbi/new', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 编辑ChatBI
|
||||
|
export function editChatBI(data: any) { |
||||
|
return request({ |
||||
|
url: '/aibot/chatbi/edit', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 删除ChatBI
|
||||
|
export function delChatBI(data: any) { |
||||
|
return request({ |
||||
|
url: '/aibot/chatbi/del', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
export interface askChatBIRequest { |
||||
|
user_query:string; |
||||
|
db_type?:string; |
||||
|
db_config?:Object; |
||||
|
} |
||||
|
// 调用chatbi
|
||||
|
export function askChatBI(data: askChatBIRequest, mode:string) { |
||||
|
return request({ |
||||
|
url: '/aibot/chatbi/api?mode='+mode, |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,156 @@ |
|||||
|
<!-- |
||||
|
@ 时间: 2025-12-30 |
||||
|
@ 备注: chatbi 服务配置界面 |
||||
|
--> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import device_panel from './device_panel.vue' |
||||
|
import ask_panel from './chatbit_ask_panel.vue' |
||||
|
import {getChatBIList,newChatBI,editChatBI,delChatBI} from "@/api/date/chatbi" |
||||
|
import { h } from 'vue' |
||||
|
import { Delete,Edit } from '@element-plus/icons-vue' |
||||
|
import { ElSelect,ElOption, ElInput,ElMessage,ElMessageBox } from 'element-plus' |
||||
|
import Chatbi_setting_panel from './chatbi_setting_panel.vue'; |
||||
|
const dataTable=ref([]) |
||||
|
const dynamicVNode = ref<VNode | null>(null) |
||||
|
const currentHoverRow=ref("") //table 行的按钮控制 |
||||
|
|
||||
|
const onChatBISetting=()=>{ |
||||
|
dynamicVNode.value=h(device_panel,{ |
||||
|
checked:[], |
||||
|
confirmFunc:(data:string[])=>{ |
||||
|
}, |
||||
|
closeFunc:()=>dynamicVNode.value=null |
||||
|
}) |
||||
|
} |
||||
|
const handleMouseEnter=(row:any)=>{ |
||||
|
currentHoverRow.value=row.uuid |
||||
|
} |
||||
|
|
||||
|
const onChatBIEditOrNew=(row:any|null)=>{ |
||||
|
const isEdit=row!==null |
||||
|
const newName=ref(isEdit?row.name:'') |
||||
|
const newType=ref(isEdit?row.type:'') |
||||
|
|
||||
|
dynamicVNode.value=h(Chatbi_setting_panel,{ |
||||
|
title: isEdit?'编辑ChatBI实例':'新建ChatBI实例', |
||||
|
name:newName.value, |
||||
|
dbtype:newType.value, |
||||
|
checked:row?row.dataset:"", |
||||
|
confirmFunc:(_name:string,_type:string, data:string[])=>{ |
||||
|
if(_name!=""){ |
||||
|
const params={ |
||||
|
name: _name, |
||||
|
type: _type, |
||||
|
dataset: data.join(",") |
||||
|
} |
||||
|
const apiCall=isEdit?editChatBI({...params,uuid:row.uuid}):newChatBI(params) |
||||
|
|
||||
|
apiCall.then(()=>{ |
||||
|
ElMessage.success(isEdit?'编辑成功':'新建成功') |
||||
|
getChatBIList().then((res:any)=>{ |
||||
|
dataTable.value=res.data||[] |
||||
|
}) |
||||
|
}).catch(()=>{ |
||||
|
ElMessage.error(isEdit?'编辑失败':'新建失败') |
||||
|
}) |
||||
|
}else{ |
||||
|
ElMessage.warning('请填写完整信息') |
||||
|
} |
||||
|
dynamicVNode.value=null |
||||
|
}, |
||||
|
closeFunc:()=>dynamicVNode.value=null |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const onChatBINew=()=>onChatBIEditOrNew(null) |
||||
|
const onEditChatBI=(row:any)=>onChatBIEditOrNew(row) |
||||
|
|
||||
|
const onDeleteChatBI=(row:any)=>{ |
||||
|
ElMessageBox.confirm(`确认删除项目( ${row.name}) ?删除后不可恢复!取消则放弃删除操作。`, "警告", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}).then(()=>{ |
||||
|
delChatBI({ |
||||
|
uuid: row.uuid |
||||
|
}).then(()=>{ |
||||
|
ElMessage.success('删除成功') |
||||
|
getChatBIList().then((res:any)=>{ |
||||
|
dataTable.value=res.data||[] |
||||
|
}) |
||||
|
}).catch(()=>{ |
||||
|
ElMessage.error('删除失败') |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const askChatBI=(row:any)=>{ |
||||
|
dynamicVNode.value = h(ask_panel, { |
||||
|
'agent': { model: true, name: row.name, uuid: row.uuid,dbm:row.type,dataset:row.dataset }, |
||||
|
'closefunc': () => dynamicVNode.value = null |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
onMounted(()=>{ |
||||
|
getChatBIList().then((res:any)=>{ |
||||
|
dataTable.value=res.data||[] |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div> |
||||
|
<el-button @click="onChatBISetting">chatbi 设置</el-button> |
||||
|
<el-button @click="onChatBINew">chatbi 新建</el-button> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-table |
||||
|
stripe |
||||
|
:data="dataTable" |
||||
|
ref="multipleTableRef" |
||||
|
:header-cell-style="{ background: '#f5f8fd' }" |
||||
|
style="width: 100%" |
||||
|
row-key="uuid" |
||||
|
:row-style ="() => ({ lineHeight: '36px' })" |
||||
|
@cell-mouse-enter="handleMouseEnter" |
||||
|
@selection-change=""> |
||||
|
|
||||
|
<el-table-column width="450" property="name" label="项目名"> |
||||
|
</el-table-column> |
||||
|
<el-table-column width="360" property="type" label="类型"> |
||||
|
<template #default="scope"> |
||||
|
<span v-if="scope.row.type=='tsd'">时序型</span> |
||||
|
<span v-else >关系型</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column width="360" label="配置"> |
||||
|
<template #default="scope"> |
||||
|
<div v-show="currentHoverRow === scope.row.uuid"> |
||||
|
<span> |
||||
|
<el-button size="small" :icon="Edit" circle @click="onEditChatBI(scope.row)"></el-button> |
||||
|
<el-button size="small" :icon="Delete" circle @click="onDeleteChatBI(scope.row)"></el-button> |
||||
|
<el-button size="small" circle @click="askChatBI(scope.row)">问</el-button> |
||||
|
</span> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
|
||||
|
<div v-if="dynamicVNode"> |
||||
|
<component :is="dynamicVNode" /> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
|
||||
|
</style> |
||||
|
|
||||
|
<style> |
||||
|
.chatbi-new-dialog { |
||||
|
width: 800px !important; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,145 @@ |
|||||
|
<!-- |
||||
|
@ 时间: 2025-12-30 |
||||
|
@ 备注: chatbi_setting_panel |
||||
|
--> |
||||
|
<script setup lang="ts"> |
||||
|
import { getOrPostDate } from "@/api/date/apidate"; |
||||
|
import { |
||||
|
dataSourceTypes, |
||||
|
interfaceTypes, |
||||
|
} from "@/api/date/type"; |
||||
|
|
||||
|
const props = withDefaults(defineProps<{ |
||||
|
title:string; |
||||
|
name:string; |
||||
|
dbtype:string; |
||||
|
checked:string, //当前勾选的数据库id |
||||
|
confirmFunc:(name:string,type:string, data:string[])=>void, //保存数据的回调, data是当前勾选的数据库id |
||||
|
closeFunc:()=>void, //父级只需销毁组件 |
||||
|
}>(),{}) |
||||
|
|
||||
|
const checkList = ref<string[]>([]) //选择的数据库id |
||||
|
const checkoptions=ref<{id:string,name:string,code:string}[]>([]) //数据库check option的数据源 |
||||
|
const newType=ref("") |
||||
|
const newName=ref("") |
||||
|
const opTotal=ref(0) |
||||
|
const dblist=ref<string[]>([]) //原有选择的数据库 |
||||
|
|
||||
|
watch(newType,(val)=>{ |
||||
|
if(val=="rdb"){ |
||||
|
onLoadData(1) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const onSaveChange=()=>{ |
||||
|
if(newType.value=="tsd") checkList.value=[] |
||||
|
props.confirmFunc(newName.value,newType.value, checkList.value) |
||||
|
} |
||||
|
|
||||
|
const onLoadData=(page:number)=>{ |
||||
|
freshPage(page) |
||||
|
} |
||||
|
|
||||
|
const freshPage=(page:number)=>{ |
||||
|
//加载数据库源 |
||||
|
let sendData = { |
||||
|
url: import.meta.env.VITE_APP_SJZT_URL + "/database/app/datasource/page", |
||||
|
methodType: "GET", |
||||
|
where: "pageNum="+page+"&pageSize=10&dataType=1" |
||||
|
}; |
||||
|
getOrPostDate("POST", sendData).then((data: any) => { |
||||
|
checkoptions.value=[] |
||||
|
opTotal.value=data.data.total; |
||||
|
if (data.data.records && data.data.records.length > 0) { |
||||
|
data.data.records.forEach((item: any) => { |
||||
|
dataSourceTypes.forEach((itemsd: any) => { |
||||
|
if (itemsd.value == item.datasourceType) { |
||||
|
item.datasourceTypeName = itemsd.label; |
||||
|
} |
||||
|
}); |
||||
|
interfaceTypes.forEach((interItem: any) => { |
||||
|
if (interItem.value == item.interfaceType) { |
||||
|
item.interfaceTypeName = interItem.label; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
checkoptions.value.push({ |
||||
|
id:item.databaseName, |
||||
|
name:item.databaseName+item.dataSourceDes, |
||||
|
code:item.databaseName}) |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
newName.value=props.name |
||||
|
newType.value=props.dbtype |
||||
|
if(props.checked!=""){ |
||||
|
checkList.value=props.checked.split(",") |
||||
|
dblist.value=props.checked.split(",") |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<el-dialog :model-value="true" :style="{'max-height': '880px'}" @close="closeFunc"> |
||||
|
<template #header> |
||||
|
<span>{{props.title}}</span> |
||||
|
</template> |
||||
|
<div class="tablelist"> |
||||
|
<el-input style="width:40%;margin:10px;" placeholder="请输入项目名称" v-model="newName"></el-input> |
||||
|
<el-select v-model="newType" style="width:40%;margin:10px;" placeholder="请选择数据库类型" valueKey="value"> |
||||
|
<el-option key="rdb" value="rdb">关系型</el-option> |
||||
|
<el-option key="tsd" value="tsd">时序型</el-option> |
||||
|
</el-select> |
||||
|
|
||||
|
<div v-if="newType=='rdb'" style="margin: 10px;"> |
||||
|
<div style="width: 100%;" >当前关联数据库: |
||||
|
<span class="dbtag" v-for="value in dblist">{{ value }}</span> |
||||
|
</div> |
||||
|
<el-checkbox-group v-model="checkList" > |
||||
|
<el-checkbox v-for="op in checkoptions" :id="op.id" :label="op.name" :value="op.code" style="width: 40%;"/> |
||||
|
</el-checkbox-group> |
||||
|
<div v-if="opTotal>10" style="margin-top: 16px;"> |
||||
|
<el-pagination size="small" @current-change="onLoadData" background layout="prev, pager, next" :total="opTotal" :page-size="10"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="closeFunc()">取消</el-button> |
||||
|
<el-button type="primary" @click="onSaveChange">保存</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.menus_tree{ |
||||
|
display: block; |
||||
|
padding: 2px; |
||||
|
margin-right: 24px; |
||||
|
box-shadow: 0px 0px 12px rgb(0 0 0 / 18%); |
||||
|
} |
||||
|
.tablelist{ |
||||
|
margin-bottom:20px; |
||||
|
display:flex; |
||||
|
flex-direction:column; |
||||
|
width: 90%; |
||||
|
} |
||||
|
|
||||
|
.checkTitle{ |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
.dbtag{ |
||||
|
background-color: #c3c1bd; |
||||
|
padding: 1px 9px; |
||||
|
border-radius: 7px; |
||||
|
margin: 0 4px; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
|
||||
|
|
||||
@ -0,0 +1,352 @@ |
|||||
|
<!-- |
||||
|
@ 作者: han2015 |
||||
|
@ 时间: 2025-05-12 15:39:13 |
||||
|
@ 备注: chatbi ask_panel |
||||
|
--> |
||||
|
<script lang="ts" setup> |
||||
|
|
||||
|
import {ElText,ElInput} from "element-plus"; |
||||
|
import {Promotion,Remove } from '@element-plus/icons-vue' |
||||
|
import { getOrPostDate } from "@/api/date/apidate"; |
||||
|
import {askChatBI} from "@/api/date/chatbi" |
||||
|
import * as echarts from 'echarts/core'; |
||||
|
import { nextTick } from 'vue' |
||||
|
|
||||
|
const props = withDefaults(defineProps<{ |
||||
|
closefunc:()=>void, |
||||
|
agent:{model:boolean,name:string,uuid:string,dbm:string,dataset:string} |
||||
|
}>(),{}) |
||||
|
|
||||
|
interface charData{ |
||||
|
dataList:Object[]; |
||||
|
dimCols:string[]; |
||||
|
measureCols:string[]; |
||||
|
} |
||||
|
|
||||
|
const myquestion=ref('') |
||||
|
const currentAgent=ref<{name:string,uuid:string,model:boolean,dbm:string}>({}) |
||||
|
const interact_msg=ref<{ask:boolean,think:string,content:string,chart?:charData}[]>([]) |
||||
|
const inputState=ref(true) |
||||
|
let relationDB={} |
||||
|
|
||||
|
//消息体 |
||||
|
interface message{ |
||||
|
ask:boolean, |
||||
|
think:string, |
||||
|
content:string |
||||
|
} |
||||
|
|
||||
|
async function onSendTextToAI(){ |
||||
|
interact_msg.value.push({ask:true,think:"",content:myquestion.value}) |
||||
|
const params={"user_query":myquestion.value} |
||||
|
if(props.agent.dbm=="rdb"){ |
||||
|
switch(relationDB.datasourceType){ |
||||
|
case "4": |
||||
|
params.db_type="sqlserver" |
||||
|
break; |
||||
|
case "8": |
||||
|
params.db_type="postgresql" |
||||
|
break; |
||||
|
default: |
||||
|
params.db_type="mysql" |
||||
|
} |
||||
|
params.db_config={ |
||||
|
host:relationDB.ipAddress, |
||||
|
port:relationDB.port, |
||||
|
database:relationDB.databaseName, |
||||
|
username:relationDB.account, |
||||
|
password:relationDB.password, |
||||
|
} |
||||
|
} |
||||
|
myquestion.value="" |
||||
|
askChatBI(params,props.agent.dbm).then((res:any)=>{ |
||||
|
interact_msg.value.push({ask:false,think:"",content:"",chart:res.data}) |
||||
|
}).catch((err:any)=>{ |
||||
|
ElMessage.error("请求异常:"+err.message) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const drawChart= async (name:string,data:Object)=>{ |
||||
|
const option= buildSmoothLineOption(data.chart) |
||||
|
await nextTick() |
||||
|
|
||||
|
const dom=document.getElementById(name) |
||||
|
if(dom){ |
||||
|
const myChart = echarts.init(dom); |
||||
|
myChart.setOption(option); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 通用转换函数 |
||||
|
const buildSmoothLineOption=(chart:any)=>{ |
||||
|
const dimKey = chart.dimCols[0]; // "时间" |
||||
|
const measureKey = chart.measureCols[0]; // "预塔塔顶压力" |
||||
|
|
||||
|
const xAxisData = chart.dataList.map(item => item[dimKey]); |
||||
|
const seriesData = chart.dataList.map(item => Number(item[measureKey])); |
||||
|
|
||||
|
const option= { |
||||
|
tooltip: {}, |
||||
|
grid:{ |
||||
|
left: 10, |
||||
|
right: 10, |
||||
|
bottom: 0, |
||||
|
top: 30, |
||||
|
containLabel: true |
||||
|
}, |
||||
|
xAxis: { |
||||
|
type: "category", |
||||
|
boundaryGap: true, |
||||
|
axisLabel: { |
||||
|
rotate: 45, // 设置标签旋转45度 |
||||
|
color: '#333', |
||||
|
fontSize: 12, |
||||
|
}, |
||||
|
data: xAxisData |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: "value", |
||||
|
}, |
||||
|
series: [{ |
||||
|
name: measureKey, |
||||
|
type: "line", |
||||
|
smooth: true, |
||||
|
data: seriesData, |
||||
|
lineStyle: { width: 2 }, |
||||
|
itemStyle: { color: "#5470c6" } |
||||
|
}], |
||||
|
dataZoom:null, |
||||
|
}; |
||||
|
|
||||
|
if (seriesData.length>100){ |
||||
|
option.dataZoom=[ |
||||
|
{ |
||||
|
type: 'slider', // 滑块型滚动条 |
||||
|
xAxisIndex: 0, // 只控制第 0 条 x 轴 |
||||
|
show: true, |
||||
|
realtime: true, // 拖拽时实时刷新 |
||||
|
start: 0, // 起始百分比 |
||||
|
end: 30, // 结束百分比(可视范围) |
||||
|
height: 5, // 滚动条本身高度 |
||||
|
bottom: 5, // 距离容器底部 |
||||
|
handleSize: '40%', |
||||
|
// handleStyle: { color: 'rgba(27,90,169,1)' }, |
||||
|
// backgroundColor: 'rgba(37,46,100,.8)', |
||||
|
// fillerColor: 'rgba(27,90,169,1)', |
||||
|
borderColor: 'transparent' |
||||
|
} |
||||
|
// // 可选:再配一个内置型(鼠标滚轮/触摸板缩放) |
||||
|
// { type: 'inside', xAxisIndex: 0 } |
||||
|
] |
||||
|
} |
||||
|
|
||||
|
return option; |
||||
|
} |
||||
|
|
||||
|
//加载当前chatbi实例绑定的数据库 |
||||
|
const getRefDatabase=(name:string)=>{ |
||||
|
//加载数据库源 |
||||
|
let sendData = { |
||||
|
url: import.meta.env.VITE_APP_SJZT_URL + "/database/app/datasource/page", |
||||
|
methodType: "GET", |
||||
|
where: `pageNum=1&databaseName=${name}&pageSize=10&dataType=1` |
||||
|
}; |
||||
|
getOrPostDate("POST", sendData).then((res: any) => { |
||||
|
if(res.data.records.length>0){ |
||||
|
relationDB=res.data.records[0] |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//渲染完页面再执行 |
||||
|
onMounted(() => { |
||||
|
currentAgent.value=props.agent |
||||
|
|
||||
|
getRefDatabase(props.agent.dataset) |
||||
|
|
||||
|
// interact_msg.value.push({ask:true,think:"",content:"预塔塔顶压力,最近一周的数据趋势"}) |
||||
|
// interact_msg.value.push({ask:false,think:"",content:"", chart:{ |
||||
|
// chart: { |
||||
|
// "dataList": [ |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:47", |
||||
|
// "name": "【2025】21期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 278271, |
||||
|
// "uuid": "fdae94f6-7fb8-491e-b075-b98595269580" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:46", |
||||
|
// "name": "【2025】18期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 287256, |
||||
|
// "uuid": "ce40f7b1-d84b-4709-adf8-4dfc83cf2882" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:46", |
||||
|
// "name": "【2025】20期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 246410, |
||||
|
// "uuid": "6e58feb4-f4e8-4eaf-9242-1ce0735e106b" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:46", |
||||
|
// "name": "【2025】19期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 306184, |
||||
|
// "uuid": "c8a14d7b-336f-4ccf-8fda-39ff9aafd7e0" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:45", |
||||
|
// "name": "【2025】15期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 212694, |
||||
|
// "uuid": "8ef700cc-a121-4cdc-87d7-ec9f090083e2" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:45", |
||||
|
// "name": "【2025】17期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 227187, |
||||
|
// "uuid": "0eb8c280-9f13-40d3-bef0-ab88946d38e5" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:45", |
||||
|
// "name": "【2025】16期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 236041, |
||||
|
// "uuid": "f97bd81b-82ad-48f0-8666-3f02f8c851de" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:44", |
||||
|
// "name": "【2025】12期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 219716, |
||||
|
// "uuid": "9b748cc9-4def-49d0-baa8-567b6bf50673" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:44", |
||||
|
// "name": "【2025】14期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 203773, |
||||
|
// "uuid": "70b045db-766c-45ca-a54a-be8df2adc396" |
||||
|
// }, |
||||
|
// { |
||||
|
// "create_time": "2026-01-09T08:43:44", |
||||
|
// "name": "【2025】13期总经理办公会暨周大调度会会议纪要.pdf", |
||||
|
// "size": 218646, |
||||
|
// "uuid": "da728907-b787-4d36-b210-820bd2632dac" |
||||
|
// } |
||||
|
// ], |
||||
|
// "dimCols": [ |
||||
|
// "create_time", |
||||
|
// "name", |
||||
|
// "uuid" |
||||
|
// ], |
||||
|
// "measureCols": [ |
||||
|
// "size" |
||||
|
// ] |
||||
|
// }, |
||||
|
// message: "已为您生成从matter表查找最新10个文件的SQL语句,包含创建时间、名称、uuid和大小信息,按创建时间降序排列。", |
||||
|
// sql: "SELECT DISTINCT create_time, name, uuid, size FROM tank31_matter ORDER BY create_time DESC LIMIT 10" |
||||
|
// }}) |
||||
|
|
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<el-drawer |
||||
|
:model-value="currentAgent.model" |
||||
|
:title="currentAgent.name+' : 问数'" |
||||
|
direction="rtl" |
||||
|
size="60%" |
||||
|
@close="props.closefunc()" |
||||
|
:style="{padding:'17px',backgroundColor:'#f3f3f3'}"> |
||||
|
<div style="position: relative;background: white;height:85%;overflow-y: auto;"> |
||||
|
<div class="reply_area" > |
||||
|
<template v-for="msg,index of interact_msg"> |
||||
|
<el-text v-if="msg.ask" class="t_ask" >{{ msg.content }}</el-text> |
||||
|
<div v-else class="t_resp"> |
||||
|
<el-text >{{ msg.chart?.message }}</el-text> |
||||
|
<div v-if="props.agent.dbm=='tsd'"> |
||||
|
<div :id="'chart_'+index" style="width: 100%;height:360px;"> |
||||
|
{{ drawChart('chart_'+index,msg.chart!) }} |
||||
|
</div> |
||||
|
</div> |
||||
|
<div v-else> |
||||
|
<el-text v-if="msg.chart?.sql" class="sql">{{ msg.chart?.sql }}</el-text> |
||||
|
<div :id="'chart_'+index" style="width: 100%;height:360px;overflow: scroll;"> |
||||
|
<el-table :data="msg.chart?.chart.dataList"> |
||||
|
<el-table-column v-for="value in msg.chart?.chart.dimCols" :prop="value" :label="value"></el-table-column> |
||||
|
<el-table-column v-for="value in msg.chart?.chart.measureCols" :prop="value" :label="value"></el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
</div> |
||||
|
<div class="question_com" :class="{newquestion:interact_msg.length>0}"> |
||||
|
<h1 v-show="interact_msg.length==0" style="font-size: 33px;font-weight: bold;margin: 10px;">恒信高科ChatBI服务</h1> |
||||
|
<el-input placeholder="问..." v-model="myquestion" input-style="border-radius: 20px;" |
||||
|
resize="none" :autosize="{minRows: 4}" type="textarea" /> |
||||
|
<el-button :style="{display :inputState ? '':'none'}" type="primary" :icon="Promotion" circle @click="onSendTextToAI"/> |
||||
|
<el-button :style="{display :inputState ? 'none':''}" type="primary" :icon="Remove" circle @click=""/> |
||||
|
<span>内容由 AI 生成,请仔细甄别</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-drawer> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.app_container { |
||||
|
padding: 10px 30px 0px 30px; |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
} |
||||
|
.newquestion{ |
||||
|
bottom: 20px; |
||||
|
} |
||||
|
.question_com{ |
||||
|
position: fixed; |
||||
|
width: 52%; |
||||
|
margin: 0 50px; |
||||
|
text-align: center; |
||||
|
display: block; |
||||
|
button{ |
||||
|
position: absolute; |
||||
|
bottom: 25px; |
||||
|
right: 5px; |
||||
|
} |
||||
|
} |
||||
|
.reply_area{ |
||||
|
display: flex; |
||||
|
min-height: 20%; |
||||
|
flex-direction: column; |
||||
|
margin: 15px 15px 110px 0px; |
||||
|
} |
||||
|
|
||||
|
.t_ask{ |
||||
|
align-self: end; |
||||
|
line-height: 34px; |
||||
|
background-color: rgb(188 211 241); |
||||
|
padding: 0 30px; |
||||
|
border-radius:10px; |
||||
|
margin: 15px; |
||||
|
} |
||||
|
.t_resp{ |
||||
|
align-self: start; |
||||
|
line-height: 30px; |
||||
|
margin: 20px 33px; |
||||
|
font-size: 16px; |
||||
|
color: black; |
||||
|
width: 92%; |
||||
|
.sql{ |
||||
|
display: block; |
||||
|
padding: 8px; |
||||
|
margin: 10px 0; |
||||
|
background: #e5e5e5; |
||||
|
color: #0a4de9; |
||||
|
border-radius: 8px; |
||||
|
white-space: pre-wrap; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
table { |
||||
|
width: 100%; |
||||
|
display: table; |
||||
|
border: 0px solid; |
||||
|
overflow: scroll; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,119 @@ |
|||||
|
<!-- |
||||
|
@ 时间: 2025-12-30 |
||||
|
@ 备注: chatbi, 设备和设备测点选择组件 |
||||
|
--> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import {getDevicesTree,getDevicesMonitors} from "@/api/date/chatbi" |
||||
|
|
||||
|
|
||||
|
const props = withDefaults(defineProps<{ |
||||
|
checked:string[], |
||||
|
confirmFunc:(data:string[])=>void, //父级组件完全接管提交流程,组件不在做相关处理 |
||||
|
closeFunc:()=>void, //父级只需销毁组件 |
||||
|
}>(),{}) |
||||
|
|
||||
|
const firstLevelKeys = ref<string[]>(["HXGK","JCFC"]) //默认展开的部门 |
||||
|
const treeData=ref([]) |
||||
|
const checkList = ref<string[]>([]) |
||||
|
const checkoptions=ref<{id:string,name:string,code:string}[]>([]) |
||||
|
const nodeName=ref("") |
||||
|
const opTotal=ref(0) |
||||
|
const currentNode=ref<{id:string}>({id:""}) |
||||
|
|
||||
|
|
||||
|
const onSaveChange=()=>{ |
||||
|
props.confirmFunc(checkList.value) |
||||
|
} |
||||
|
|
||||
|
const onSelectDevice=(node)=>{ |
||||
|
nodeName.value=node.label |
||||
|
currentNode.value=node |
||||
|
freshPage(1) |
||||
|
} |
||||
|
|
||||
|
const onLoadData=(page:number)=>{ |
||||
|
freshPage(page) |
||||
|
} |
||||
|
|
||||
|
const freshPage=(page:number)=>{ |
||||
|
getDevicesMonitors({ |
||||
|
deviceCode:currentNode.value?.id, |
||||
|
rows:30, |
||||
|
page:page |
||||
|
}).then(res=>{ |
||||
|
checkoptions.value=[] |
||||
|
opTotal.value=0 |
||||
|
if(res.status==200){ |
||||
|
opTotal.value=res.data.total |
||||
|
res.data.rows?.forEach(row => { |
||||
|
checkoptions.value.push({id:row.id,name:row.name,code:row.code}) |
||||
|
}); |
||||
|
}else{ |
||||
|
ElMessage.error('测点获取失败!') |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
checkList.value=props.checked |
||||
|
getDevicesTree().then((res)=>{ |
||||
|
treeData.value = res.data |
||||
|
}) |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<el-dialog :model-value="true" :style="{'max-height': '880px'}" @close="closeFunc"> |
||||
|
<template #header> |
||||
|
<span>请选择设备测点</span> |
||||
|
</template> |
||||
|
<div style="display: grid;width: 100%;grid-template-columns:1fr 2fr;"> |
||||
|
<div class="menus_tree"> |
||||
|
<el-tree |
||||
|
ref="treeRef" |
||||
|
:data="treeData" |
||||
|
node-key="id" |
||||
|
:check-on-click-leaf="false" |
||||
|
:style="{maxHeight:'500px','overflow-y': 'auto'}" |
||||
|
:props="{label: 'label',children:'children',isLeaf:'children'}" |
||||
|
:default-expanded-keys="firstLevelKeys" |
||||
|
@node-click="onSelectDevice" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="tablelist"> |
||||
|
<div class="checkTitle" v-if="checkoptions.length==0&&nodeName!=''">{{nodeName}}: 没有测点!</div> |
||||
|
<div class="checkTitle" v-else>当前节点:{{nodeName}} </div> |
||||
|
<el-checkbox-group v-model="checkList" > |
||||
|
<el-checkbox v-for="op in checkoptions" :id="op.id" :label="op.name" :value="op.code" /> |
||||
|
</el-checkbox-group> |
||||
|
<div v-if="opTotal>30" style="margin-top: 16px;"> |
||||
|
<el-pagination size="small" @current-change="onLoadData" background layout="prev, pager, next" :total="opTotal" :page-size="30"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button @click="closeFunc()">取消</el-button> |
||||
|
<el-button type="primary" @click="onSaveChange">保存</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.menus_tree{ |
||||
|
display: block; |
||||
|
padding: 2px; |
||||
|
margin-right: 24px; |
||||
|
box-shadow: 0px 0px 12px rgb(0 0 0 / 18%); |
||||
|
} |
||||
|
|
||||
|
.checkTitle{ |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
|
||||
|
|
||||
Loading…
Reference in new issue