wujingjing
2024-12-16 bec33d7bb69818d4f8cf117e315de66c85ebf613
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
<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>