<template>
|
<AHMContainer type="card">
|
<template #aside>
|
<!-- 目录树 -->
|
<LeftTreeByMgr
|
v-loading="treeLoading"
|
class="h100"
|
ref="leftTreeRef"
|
:defaultProps="{
|
id: 'group_id',
|
label: 'group_name',
|
children: 'children',
|
}"
|
:treedata="listLeftData"
|
title-name="场景列表"
|
:show-more-operate="false"
|
:show-add="false"
|
:current-node-key="currentListID"
|
:node-icon="() => 'ele-Document'"
|
@click="handleClickNode"
|
defaultExpandAll
|
>
|
</LeftTreeByMgr>
|
</template>
|
<template #header>
|
<el-form :inline="true" :model="queryParams">
|
<el-form-item label="名称" prop="title">
|
<el-input
|
v-model="queryParams.title"
|
style="width: 226.4px"
|
placeholder="文件名称"
|
clearable
|
@input="debounceQueryTable"
|
></el-input>
|
</el-form-item>
|
<el-form-item>
|
<el-button icon="ele-Refresh" @click="resetQuery">重置 </el-button>
|
<el-button icon="ele-Plus" @click="openOptDlg()" type="primary"> 添加 </el-button>
|
</el-form-item>
|
</el-form>
|
</template>
|
<template #main>
|
<div class="flex-auto flex-column h-full">
|
<el-table
|
v-loading="workFlowDataLoading"
|
ref="draggableFormulaTableRef"
|
border
|
row-key="id"
|
class="flex-auto"
|
:row-class-name="isFormulaTableDrag ? 'cursor-move' : 'cursor-pointer'"
|
:header-cell-style="{ textAlign: 'center' }"
|
:data="displayTableData"
|
highlight-current-row
|
>
|
<el-table-column prop="title" label="工作流名称" fixed="left" show-overflow-tooltip align="left" />
|
<el-table-column prop="prompt" width="280" label="工作流提示" show-overflow-tooltip align="center"> </el-table-column>
|
<el-table-column prop="published" width="120" label="发布状态" show-overflow-tooltip align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.published === SupervisorPublished.Y ? 'primary' : 'info'">{{
|
supervisorPublishedMap[scope.row.published]
|
}}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="create_user" width="100" label="创建者" show-overflow-tooltip align="center" />
|
<el-table-column prop="create_time" width="180" label="创建时间" show-overflow-tooltip align="center" />
|
<el-table-column prop="note" width="180" label="说明" show-overflow-tooltip align="center" />
|
<el-table-column label="操作" width="120" fixed="right" show-overflow-tooltip align="center">
|
<template #default="scope">
|
<div class="space-x-2.5">
|
<el-tooltip effect="dark" content="编辑" placement="top">
|
<i class="ywifont ywicon-bianji !text-[15px] text-blue-400 cursor-pointer" @click="openOptDlg(scope.row)"></i>
|
</el-tooltip>
|
<el-tooltip effect="dark" content="测试工作流" placement="top">
|
<i class="ywifont ywicon-ceshi !text-[20px] text-blue-400 cursor-pointer" @click="openChatTest(scope.row)"></i>
|
</el-tooltip>
|
<el-tooltip effect="dark" content="工作流设计" placement="top">
|
<i
|
class="ywifont ywicon-jiegousheji !text-[15px] text-blue-400 cursor-pointer"
|
@click="gotoFlowDesign(scope.row)"
|
></i>
|
</el-tooltip>
|
|
<el-tooltip effect="dark" content="删除" placement="top">
|
<i
|
class="ywifont ywicon-shanchu !text-[17px] text-red-400 cursor-pointer"
|
@click="deleteCurrentFormulaRow(scope.row)"
|
></i>
|
</el-tooltip>
|
</div>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</template>
|
<OptDlg
|
v-model="optDlgIsShow"
|
:item="optDlgMapRow"
|
@insert="insertOpt"
|
:currentListID="currentListID"
|
@update="updateOpt"
|
></OptDlg>
|
<div
|
v-if="chatTestIsShow"
|
ref="draggableChatRef"
|
:style="style"
|
class="fixed z-50 w-[700px] h-[800px] flex flex-col bg-[rgb(239,244,253)] right-0 bottom-0 rounded-lg"
|
>
|
<div ref="chatDragHandlerRef" class="flex-0">
|
<div class="flex items-center justify-between py-2 px-4">
|
<div class="font-bold cursor-move">
|
WI水务智能管家——【{{ chatTestMapRow?.title }}】测试
|
<!-- <img src="/static/images/logo/logo-mini.svg" width="10" height="10" /> -->
|
</div>
|
<i class="ywifont ywicon-guanbi font-[10px] font-bold cursor-pointer" @click="closeChatTest"></i>
|
</div>
|
</div>
|
<Chat ref="chatRef" class="flex-auto px-2" :questionApi="questionAi"> </Chat>
|
</div>
|
</AHMContainer>
|
</template>
|
|
<script setup lang="ts">
|
import { useDraggable } from '@vueuse/core';
|
import type { CancelTokenSource } from 'axios';
|
import axios from 'axios';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
import OptDlg from './optDlg/OptDlg.vue';
|
import * as agentGroupApi from '/@/api/ai/agentGroup';
|
import { check_workflow_agent_validate, delete_workflow_agent, get_workflow_agent_list } from '/@/api/workflow/index';
|
import Chat from '/@/components/chat/Chat.vue';
|
import AHMContainer from '/@/components/layout/AHMContainer.vue';
|
import LeftTreeByMgr from '/@/components/tree/leftTreeByMgr.vue';
|
import { useQueryTable } from '/@/hooks/useQueryTable';
|
import router from '/@/router';
|
import { useCompRef } from '/@/utils/types';
|
import { convertListToTree, debounce, travelTree } from '/@/utils/util';
|
import { SupervisorPublished, supervisorPublishedMap } from '/@/views/project/yw/lowCode/sqlAmis/types';
|
//#region ====================== 左侧树数据,tree init ======================
|
const leftTreeRef = useCompRef(LeftTreeByMgr);
|
const treeLoading = ref(false);
|
const listLeftData = ref([]);
|
const currentListID = computed(() => currentNode.value?.group_id);
|
const currentNode = ref(null);
|
const handleClickNode = (data) => {
|
nextTick(() => {
|
leftTreeRef.value?.treeRef.setCurrentKey(data.group_id);
|
});
|
currentNode.value = data;
|
tableData.value = data.sampleList;
|
};
|
//#endregion
|
//#region ====================== 工作流列表 ======================
|
const workFlowDataLoading = ref(false);
|
const isFormulaTableDrag = ref(false);
|
const tree_update_data = ref([]);
|
const work_update_data = ref([]);
|
const tableData = ref([]);
|
//获取场景list
|
const initData = async () => {
|
const [treeData, workData] = await Promise.all([agentGroupApi.getSceneGroupTreeByPost(), get_workflow_agent_list()]);
|
const tree_Data = treeData.groups ?? [];
|
const work_Data = workData.values ?? [];
|
tree_update_data.value = tree_Data;
|
work_update_data.value = work_Data;
|
const byParent_Data = updateSampleListsAndGroupNames(tree_Data, work_Data);
|
listLeftData.value = byParent_Data;
|
const firstListTreeNode = byParent_Data[0];
|
tableData.value = firstListTreeNode.sampleList;
|
currentNode.value = firstListTreeNode;
|
};
|
// 删除一条数据
|
const deleteCurrentFormulaRow = (row: any) => {
|
ElMessageBox.confirm(`确定删除工作流:【${row.title}】?`, '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning',
|
}).then(async () => {
|
const res = await delete_workflow_agent({
|
agent_id: row.id,
|
});
|
|
if (res.json_ok) {
|
ElMessage.success('删除工作流成功');
|
const index = tableData.value.findIndex((d) => d.id === row.id);
|
tableData.value.splice(index, 1);
|
work_update_data.value = work_update_data.value.filter((work) => work.id !== row.id);
|
removeDataAndRecalculateGroupNames(tree_update_data.value, work_update_data.value, row.id);
|
} else {
|
ElMessage.error('删除工作流失败' + (res?.json_msg ? `,${JSON.stringify(res.json_msg)}` : ''));
|
}
|
});
|
};
|
// 更新树形结构和工作流列表
|
const updateSampleListsAndGroupNames = (tree_Data, work_Data) => {
|
let new_tree_Data = [];
|
tree_Data.forEach((node, index) => {
|
new_tree_Data.push(node);
|
});
|
// 为每个节点关联工作流数据
|
new_tree_Data.forEach((node) => {
|
node.sampleList = work_Data
|
.filter((work) => work.agent_group === node.group_id)
|
.map((work) => ({
|
...work,
|
published: work.published,
|
create_user: work.create_user,
|
create_time: work.create_time,
|
prompt: work.supervisor.prompt,
|
note: work.note,
|
}));
|
if (node.p_group_id) {
|
node.group_name = node.group_name.replace(/ \([^)]*\)$/, '') + ` (${node.sampleList.length})`;
|
}
|
});
|
|
// 将列表转换为树形结构
|
const byParentData = convertListToTree(new_tree_Data, {
|
ID: 'group_id',
|
ParentID: 'p_group_id',
|
Children: 'children',
|
});
|
const updatedByParentData = byParentData.reduce((accumulator, item) => {
|
// 处理子节点,累加sampleList
|
if (item.children && item.children.length > 0) {
|
item.children.forEach((child_node) => {
|
item.sampleList = item.sampleList.concat(child_node.sampleList);
|
});
|
}
|
// 移除旧的计数并添加新的计数
|
item.group_name = item.group_name.replace(/ \([^)]*\)$/, '') + ` (${item.sampleList.length})`;
|
// 将当前项添加到累加器中
|
accumulator.push(item);
|
// 返回累加器
|
return accumulator;
|
}, []); // 初始化累加器为空数组
|
|
return updatedByParentData;
|
};
|
// 插入一条数据时调用
|
const addDataAndRecalculateGroupNames = (new_tree_Data, work_Data, newWorkData) => {
|
// 添加新数据到 work_Data
|
work_Data.push(newWorkData);
|
// 重新计算工作流列表和组名
|
return updateSampleListsAndGroupNames(new_tree_Data, work_Data);
|
};
|
// 删除一条数据时调用
|
const removeDataAndRecalculateGroupNames = (new_tree_Data, work_Data, workIdToRemove) => {
|
// 过滤掉要删除的数据
|
work_Data = work_Data.filter((work) => work.id !== workIdToRemove);
|
// 重新计算工作流列表和组名
|
return updateSampleListsAndGroupNames(new_tree_Data, work_Data);
|
};
|
|
//#endregion
|
//#region ====================== 表格查询、排序,search form init ======================
|
|
const queryParams = ref({
|
title: '',
|
});
|
const { resetQuery, handleQueryTable, displayTableData } = useQueryTable(tableData, queryParams, () => {
|
displayTableData.value = tableData.value;
|
});
|
const debounceQueryTable = debounce(handleQueryTable, 400);
|
//#endregion
|
//#region ====================== 添加修改操作 ======================
|
const optDlgIsShow = ref(false);
|
const optDlgMapRow = ref(null);
|
const openOptDlg = (row?: any) => {
|
optDlgMapRow.value = row;
|
optDlgIsShow.value = true;
|
};
|
|
const updateOpt = (formValue) => {
|
travelTree(tableData.value, (value, index, array) => {
|
if (value.id === formValue.id) {
|
array[index] = {
|
...array[index],
|
...formValue,
|
};
|
return true;
|
}
|
});
|
};
|
//新增一条信息
|
const insertOpt = (newData) => {
|
const itemToAdd = {
|
...newData,
|
supervisor: {
|
...newData.supervisor, // 保留原有的 supervisor 属性
|
prompt: newData.prompt, // 但确保 prompt 是最新的
|
},
|
};
|
tableData.value.unshift(itemToAdd);
|
addDataAndRecalculateGroupNames(tree_update_data.value, work_update_data.value, itemToAdd);
|
};
|
//#endregion
|
|
//#region ====================== Chat 测试 ======================
|
const chatRef = useCompRef(Chat);
|
const chatTestMapRow = ref(null);
|
const chatTestIsShow = ref(false);
|
const openChatTest = (row) => {
|
chatTestMapRow.value = row;
|
chatTestIsShow.value = true;
|
nextTick(() => {
|
chatRef.value.clear();
|
});
|
};
|
|
const closeChatTest = () => {
|
chatTestMapRow.value = null;
|
chatTestIsShow.value = false;
|
};
|
|
const draggableChatRef = ref<HTMLElement | null>(null);
|
const chatDragHandlerRef = ref<HTMLDivElement>(null);
|
const { x, y, style } = useDraggable(draggableChatRef, {
|
handle: chatDragHandlerRef,
|
initialValue: {
|
x: document.body.clientWidth / 2 - 350,
|
y: document.body.clientHeight / 2 - 400,
|
},
|
});
|
|
const questionAi = async (text, sourceObj: { source: CancelTokenSource }) => {
|
const currentSource = axios.CancelToken.source();
|
sourceObj.source = currentSource;
|
const res = await check_workflow_agent_validate(
|
{
|
agent_id: chatTestMapRow.value.id,
|
question: text,
|
},
|
{
|
loading: false,
|
cancelToken: currentSource.token,
|
}
|
);
|
return res;
|
};
|
//#endregion
|
|
//#region ====================== 工作流设计 ======================
|
const gotoFlowDesign = (row) => {
|
router.push({
|
name: 'FlowApp',
|
query: {
|
id: row.id,
|
},
|
});
|
};
|
//#endregion
|
|
onMounted(async () => {
|
initData();
|
});
|
</script>
|
<style scoped lang="scss">
|
.set-permission {
|
padding-block: 16px;
|
padding-block-end: 0;
|
}
|
.set-form {
|
display: block;
|
box-sizing: border-box;
|
height: 100%;
|
padding-block: 16px;
|
.set-form-item {
|
font-weight: 500;
|
color: #667085;
|
font-size: 14px;
|
}
|
}
|
</style>
|