diff --git a/.env.development b/.env.development index a8b8cec..a578732 100644 --- a/.env.development +++ b/.env.development @@ -1,17 +1,14 @@ -# 页面标题 -VITE_APP_TITLE = 招商车研物联网平台 - -# 开发环境配置 -VITE_APP_ENV = 'development' - -# 招商车研物联网平台/开发环境 -VITE_APP_BASE_API = '/dev-api' - -VITE_API_URL = http://10.148.20.34:13080 -VITE_WS_URL = ws://10.148.20.34:13080/ws -# VITE_API_URL = http://10.148.108.95:13080 //杨溪IP -# VITE_API_URL = http://10.148.108.58:13080 //赵培利IP - -#node-red 服务地址 -#VITE_NODE_RED_URL = 'http://10.148.20.34:13080' -VITE_NODE_RED_URL = 'http://10.148.108.59:1880' +# 页面标题 +VITE_APP_TITLE = 招商车研物联网平台 + +# 开发环境配置 +VITE_APP_ENV = 'development' + +# 招商车研物联网平台/开发环境 +VITE_APP_BASE_API = '/dev-api' + +VITE_API_URL = http://192.168.0.100:13080 +VITE_WS_URL = ws://192.168.0.100:13080/ws +# VITE_API_URL = http://10.148.108.95:13080 //杨溪IP +# VITE_API_URL = http://10.148.108.58:13080 //赵培利IP + diff --git a/src/api/vi/corpus.js b/src/api/vi/corpus.js new file mode 100644 index 0000000..5089b57 --- /dev/null +++ b/src/api/vi/corpus.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询语料库列表 +export function listCorpus(query) { + return request({ + url: '/vi/corpus/list', + method: 'get', + params: query + }) +} + +// 查询语料库详细 +export function getCorpus(corpusId) { + return request({ + url: '/vi/corpus/' + corpusId, + method: 'get' + }) +} + +// 新增语料库 +export function addCorpus(data) { + return request({ + url: '/vi/corpus', + method: 'post', + data: data + }) +} + +// 修改语料库 +export function updateCorpus(data) { + return request({ + url: '/vi/corpus', + method: 'put', + data: data + }) +} + +// 删除语料库 +export function delCorpus(corpusId) { + return request({ + url: '/vi/corpus/' + corpusId, + method: 'delete' + }) +} diff --git a/src/main.js b/src/main.js index 11f6e4f..f52695b 100644 --- a/src/main.js +++ b/src/main.js @@ -88,7 +88,7 @@ app.use(ElementPlus, { app.use(WebSocketPlugin, { // url: import.meta.env.VITE_WS_URL, - url: 'ws://127.0.0.1:13080/ws', + url: 'ws://192.168.0.100:13080/ws', // url: 'ws://10.148.209.5:13080/ws', userId: 'your_user_id' }); diff --git a/src/permission.js b/src/permission.js index 6063a3b..9114f1a 100644 --- a/src/permission.js +++ b/src/permission.js @@ -1,73 +1,73 @@ -import router from './router' -import { ElMessage } from 'element-plus' -import NProgress from 'nprogress' -import 'nprogress/nprogress.css' -import { getToken } from '@/utils/auth' -import { isHttp, isPathMatch } from '@/utils/validate' -import { isRelogin } from '@/utils/request' -import useUserStore from '@/store/modules/user' -import useSettingsStore from '@/store/modules/settings' -import usePermissionStore from '@/store/modules/permission' - -NProgress.configure({ showSpinner: false }) - -const whiteList = ['/login', '/register'] - -const isWhiteList = (path) => { - return whiteList.some(pattern => isPathMatch(pattern, path)) -} - -router.beforeEach((to, from, next) => { - if (to.meta?.noLogin) { - next() - return - } - NProgress.start() - if (getToken()) { - to.meta.title && useSettingsStore().setTitle(to.meta.title) - /* has token*/ - if (to.path === '/login') { - next({ path: '/' }) - NProgress.done() - } else if (isWhiteList(to.path)) { - next() - } else { - if (useUserStore().roles.length === 0) { - isRelogin.show = true - // 判断当前用户是否已拉取完user_info信息 - useUserStore().getInfo().then(() => { - isRelogin.show = false - usePermissionStore().generateRoutes().then(accessRoutes => { - // 根据roles权限生成可访问的路由表 - accessRoutes.forEach(route => { - if (!isHttp(route.path)) { - router.addRoute(route) // 动态添加可访问路由表 - } - }) - next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 - }) - }).catch(err => { - useUserStore().logOut().then(() => { - ElMessage.error(err) - next({ path: '/' }) - }) - }) - } else { - next() - } - } - } else { - // 没有token - if (isWhiteList(to.path)) { - // 在免登录白名单,直接进入 - next() - } else { - next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 - NProgress.done() - } - } -}) - -router.afterEach(() => { - NProgress.done() -}) +import router from './router' +import { ElMessage } from 'element-plus' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import { getToken } from '@/utils/auth' +import { isHttp, isPathMatch } from '@/utils/validate' +import { isRelogin } from '@/utils/request' +import useUserStore from '@/store/modules/user' +import useSettingsStore from '@/store/modules/settings' +import usePermissionStore from '@/store/modules/permission' + +NProgress.configure({ showSpinner: false }) + +const whiteList = ['/login', '/register'] + +const isWhiteList = (path) => { + return whiteList.some(pattern => isPathMatch(pattern, path)) +} + +router.beforeEach((to, from, next) => { + if (to.meta?.noLogin) { + next() + return + } + NProgress.start() + if (getToken()) { + to.meta.title && useSettingsStore().setTitle(to.meta.title) + /* has token*/ + if (to.path === '/login') { + next({ path: '/' }) + NProgress.done() + } else if (isWhiteList(to.path)) { + next() + } else { + if (useUserStore().roles.length === 0) { + isRelogin.show = true + // 判断当前用户是否已拉取完user_info信息 + useUserStore().getInfo().then(() => { + isRelogin.show = false + usePermissionStore().generateRoutes().then(accessRoutes => { + // 根据roles权限生成可访问的路由表 + accessRoutes.forEach(route => { + if (!isHttp(route.path)) { + router.addRoute(route) // 动态添加可访问路由表 + } + }) + next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 + }) + }).catch(err => { + useUserStore().logOut().then(() => { + ElMessage.error(err) + next({ path: '/' }) + }) + }) + } else { + next() + } + } + } else { + // 没有token + if (isWhiteList(to.path)) { + // 在免登录白名单,直接进入 + next() + } else { + next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 + NProgress.done() + } + } +}) + +router.afterEach(() => { + NProgress.done() +}) diff --git a/src/plugins/tab.js b/src/plugins/tab.js index 7b51cf5..004aa86 100644 --- a/src/plugins/tab.js +++ b/src/plugins/tab.js @@ -1,69 +1,69 @@ -import useTagsViewStore from '@/store/modules/tagsView' -import router from '@/router' - -export default { - // 刷新当前tab页签 - refreshPage(obj) { - const { path, query, matched } = router.currentRoute.value; - if (obj === undefined) { - matched.forEach((m) => { - if (m.components && m.components.default && m.components.default.name) { - if (!['Layout', 'ParentView'].includes(m.components.default.name)) { - obj = { name: m.components.default.name, path: path, query: query }; - } - } - }); - } - return useTagsViewStore().delCachedView(obj).then(() => { - const { path, query } = obj - router.replace({ - path: '/redirect' + path, - query: query - }) - }) - }, - // 关闭当前tab页签,打开新页签 - closeOpenPage(obj) { - useTagsViewStore().delView(router.currentRoute.value); - if (obj !== undefined) { - return router.push(obj); - } - }, - // 关闭指定tab页签 - closePage(obj) { - if (obj === undefined) { - return useTagsViewStore().delView(router.currentRoute.value).then(({ visitedViews }) => { - const latestView = visitedViews.slice(-1)[0] - if (latestView) { - return router.push(latestView.fullPath) - } - return router.push('/'); - }); - } - return useTagsViewStore().delView(obj); - }, - // 关闭所有tab页签 - closeAllPage() { - return useTagsViewStore().delAllViews(); - }, - // 关闭左侧tab页签 - closeLeftPage(obj) { - return useTagsViewStore().delLeftTags(obj || router.currentRoute.value); - }, - // 关闭右侧tab页签 - closeRightPage(obj) { - return useTagsViewStore().delRightTags(obj || router.currentRoute.value); - }, - // 关闭其他tab页签 - closeOtherPage(obj) { - return useTagsViewStore().delOthersViews(obj || router.currentRoute.value); - }, - // 打开tab页签 - openPage(url) { - return router.push(url); - }, - // 修改tab页签 - updatePage(obj) { - return useTagsViewStore().updateVisitedView(obj); - } -} +import useTagsViewStore from '@/store/modules/tagsView' +import router from '@/router' + +export default { + // 刷新当前tab页签 + refreshPage(obj) { + const { path, query, matched } = router.currentRoute.value; + if (obj === undefined) { + matched.forEach((m) => { + if (m.components && m.components.default && m.components.default.name) { + if (!['Layout', 'ParentView'].includes(m.components.default.name)) { + obj = { name: m.components.default.name, path: path, query: query }; + } + } + }); + } + return useTagsViewStore().delCachedView(obj).then(() => { + const { path, query } = obj + router.replace({ + path: '/redirect' + path, + query: query + }) + }) + }, + // 关闭当前tab页签,打开新页签 + closeOpenPage(obj) { + useTagsViewStore().delView(router.currentRoute.value); + if (obj !== undefined) { + return router.push(obj); + } + }, + // 关闭指定tab页签 + closePage(obj) { + if (obj === undefined) { + return useTagsViewStore().delView(router.currentRoute.value).then(({ visitedViews }) => { + const latestView = visitedViews.slice(-1)[0] + if (latestView) { + return router.push(latestView.fullPath) + } + return router.push('/'); + }); + } + return useTagsViewStore().delView(obj); + }, + // 关闭所有tab页签 + closeAllPage() { + return useTagsViewStore().delAllViews(); + }, + // 关闭左侧tab页签 + closeLeftPage(obj) { + return useTagsViewStore().delLeftTags(obj || router.currentRoute.value); + }, + // 关闭右侧tab页签 + closeRightPage(obj) { + return useTagsViewStore().delRightTags(obj || router.currentRoute.value); + }, + // 关闭其他tab页签 + closeOtherPage(obj) { + return useTagsViewStore().delOthersViews(obj || router.currentRoute.value); + }, + // 打开tab页签 + openPage(url) { + return router.push(url); + }, + // 修改tab页签 + updatePage(obj) { + return useTagsViewStore().updateVisitedView(obj); + } +} diff --git a/src/utils/flow.js b/src/utils/flow.js index 9fdf404..e00c5c1 100644 --- a/src/utils/flow.js +++ b/src/utils/flow.js @@ -1,210 +1,221 @@ -export const getInput = (nodeId, isStrict = true) => { - const data = lf.getGraphData(); - let flag = false - if (isStrict) { - data.edges.forEach(item => { - if (item.targetNodeId === nodeId) { - flag = true - } - }); - } else { - flag = true - } - - if (flag) { - const arr = [] - data.nodes.forEach(item => { - if (item.id === nodeId) { - return - } - - if (item.properties.inputParams) { - const obj = { - value: item.id, - label: item.properties.name, - children: [] - } - const optionData = transformTree(item.properties.inputParams, obj.children) - obj.children.push(optionData) - arr.push(obj) - } - if (item.properties.nodeParams) { - const obj = { - value: item.id, - label: item.properties.name, - children: [] - } - const optionData = transformTree(item.properties.nodeParams, obj.children) - obj.children.push(optionData) - arr.push(obj) - } - }) - return arr - } - return flag -} - -const transformTree = (arr, parent = []) => { - arr.forEach(item => { - const currentNode = { - value: item.name, - label: item.name, - children: [] - }; - parent.push(currentNode); - - if (item.children?.length > 0) { - transformTree(item.children, currentNode.children); - } else { - delete currentNode.children - } - }); - return parent; -}; - -export const getStartNodeFormData = () => { - const flowData = lf.getGraphData(); - const startNode = flowData.nodes.find(item => item.type === 'start') - const data = addValueProperty(startNode.properties?.inputParams || []) - return data -} - -export const addValueProperty = (data) => { - // 处理单个对象或对象数组 - const processItem = (item, index, path) => { - // 根据类型设置默认值 - item.value = ''; - item.propPath = `${path}.${index}.` - if (item.type.includes('array') && !item.type.includes('object')) { - const type = item.type.match(/<([^>]+)>/)[1] - item.children = [{ name: 'Array Item', type, value: '', propPath: item.propPath + '.0'}] - } - // 递归处理子项 - if (item.children && item.children.length > 0) { - item.children = item.children.map((cItem, cIndex) => { - return processItem(cItem, cIndex , item.propPath + 'children') - }); - } - - return item; - }; - - // 如果传入的是数组,处理每个元素;否则处理单个对象 - return Array.isArray(data) ? data.map((item, index) => processItem(item, index, '')) : processItem(data, 0, '') -} - -export const recursiveFilter = (data, id, type = ['loop', 'customGroup'], result = []) => { - data.forEach((item) => { - if (type.includes(item.type) && item.children && item.children.includes(id)) { - result.push(item) - recursiveFilter(data, item.id, result) - } - }); - return result -} - -export const formatTableData = (arr, data = {}) => { - arr.forEach(item => { - data[item.name] = item.value - if (item?.children && item.children.length > 0) { - data[item.name] = {} - formatTableData(item.children, data[item.name]) - } - }) - return data -} - -export const addNewEdge = (nodeId) => { - const { edges } = lf.getGraphData(); - const arr = JSON.parse(JSON.stringify(edges)) - arr.forEach(_edge => { - const { sourceNodeId, targetNodeId, sourceAnchorId, targetAnchorId } = _edge - if (sourceNodeId === nodeId || targetNodeId === nodeId) { - lf.deleteEdge(_edge.id); - lf.addEdge({ - type: "bezier", - sourceNodeId: sourceNodeId, - targetNodeId: targetNodeId, - sourceAnchorId: sourceAnchorId, - targetAnchorId: targetAnchorId - }); - } - }) -} - -export const getInputNumber = (nodeId) => { - const data = lf.getGraphData(); - let flag = false - data.edges.forEach(item => { - if (item.targetNodeId === nodeId) { - flag = true - } - }); - if (flag) { - const arr = [] - data.nodes.forEach(item => { - if (item.properties.inputParams) { - item.properties.inputParams.forEach(item => { - if (item.type === 'number') { - arr.push(item) - } - }) - } - }) - return arr - } - return flag -} - -export const removeSwitchEdge = (nodeId, sourceAnchorId) => { - const { edges } = lf.getGraphData(); - const edge = edges.find(item => { - return item.sourceNodeId === nodeId && item.sourceAnchorId === sourceAnchorId - }) - - if (edge) { - lf.deleteEdge(edge.id); - } -} - -export const convertToTree = (data) => { - // 创建 id 到节点的映射 - const nodeMap = new Map(); - data.forEach(node => { - nodeMap.set(node.id, { ...node, name: node.properties.name || '' }); // 浅拷贝节点 - }); - - // 标记非根节点(被其他节点引用的节点) - const nonRootIds = new Set(); - data.forEach(node => { - if (node.children) { - node.children.forEach(childId => { - nonRootIds.add(childId); - }); - } - }); - - // 构建树形结构 - const result = []; - data.forEach(node => { - // 只处理根节点(未被引用的节点) - if (!nonRootIds.has(node.id)) { - const rootNode = nodeMap.get(node.id); - // 递归处理子节点 - const processNode = (currentNode) => { - if (currentNode.children) { - currentNode.children = currentNode.children.map(childId => { - const childNode = nodeMap.get(childId); - processNode(childNode); // 递归处理子节点 - return childNode; - }); - } - return currentNode; - }; - - result.push(processNode(rootNode)); - } - }); - - return result; +export const getInput = (nodeId, isStrict = true) => { + const data = lf.getGraphData(); + let flag = false + if (isStrict) { + data.edges.forEach(item => { + if (item.targetNodeId === nodeId) { + flag = true + } + }); + } else { + flag = true + } + + if (flag) { + const arr = [] + data.nodes.forEach(item => { + if (item.id === nodeId) { + return + } + + if (item.properties.inputParams) { + const obj = { + value: item.id, + label: item.properties.name, + children: [] + } + const optionData = transformTree(item.properties.inputParams, obj.children) + obj.children.push(optionData) + arr.push(obj) + } + if (item.properties.nodeParams) { + const obj = { + value: item.id, + label: item.properties.name + '(输入)', + children: [] + } + const optionData = transformTree(item.properties.nodeParams, obj.children) + obj.children.push(optionData) + arr.push(obj) + } + + if (item.properties.outputParams) { + const obj = { + value: item.id, + label: item.properties.name + '(输出)', + children: [] + } + const optionData = transformTree(item.properties.outputParams, obj.children) + obj.children.push(optionData) + arr.push(obj) + } + }) + return arr + } + return flag +} + +const transformTree = (arr, parent = []) => { + arr.forEach(item => { + const currentNode = { + value: item.name, + label: item.name, + children: [] + }; + parent.push(currentNode); + + if (item.children?.length > 0) { + transformTree(item.children, currentNode.children); + } else { + delete currentNode.children + } + }); + return parent; +}; + +export const getStartNodeFormData = () => { + const flowData = lf.getGraphData(); + const startNode = flowData.nodes.find(item => item.type === 'start') + const data = addValueProperty(startNode.properties?.inputParams || []) + return data +} + +export const addValueProperty = (data) => { + // 处理单个对象或对象数组 + const processItem = (item, index, path) => { + // 根据类型设置默认值 + item.value = ''; + item.propPath = `${path}.${index}.` + if (item.type.includes('array') && !item.type.includes('object')) { + const type = item.type.match(/<([^>]+)>/)[1] + item.children = [{ name: 'Array Item', type, value: '', propPath: item.propPath + '.0'}] + } + // 递归处理子项 + if (item.children && item.children.length > 0) { + item.children = item.children.map((cItem, cIndex) => { + return processItem(cItem, cIndex , item.propPath + 'children') + }); + } + + return item; + }; + + // 如果传入的是数组,处理每个元素;否则处理单个对象 + return Array.isArray(data) ? data.map((item, index) => processItem(item, index, '')) : processItem(data, 0, '') +} + +export const recursiveFilter = (data, id, type = ['loop', 'customGroup'], result = []) => { + data.forEach((item) => { + if (type.includes(item.type) && item.children && item.children.includes(id)) { + result.push(item) + recursiveFilter(data, item.id, result) + } + }); + return result +} + +export const formatTableData = (arr, data = {}) => { + arr.forEach(item => { + data[item.name] = item.value + if (item?.children && item.children.length > 0) { + data[item.name] = {} + formatTableData(item.children, data[item.name]) + } + }) + return data +} + +export const addNewEdge = (nodeId) => { + const { edges } = lf.getGraphData(); + const arr = JSON.parse(JSON.stringify(edges)) + arr.forEach(_edge => { + const { sourceNodeId, targetNodeId, sourceAnchorId, targetAnchorId } = _edge + if (sourceNodeId === nodeId || targetNodeId === nodeId) { + lf.deleteEdge(_edge.id); + lf.addEdge({ + type: "bezier", + sourceNodeId: sourceNodeId, + targetNodeId: targetNodeId, + sourceAnchorId: sourceAnchorId, + targetAnchorId: targetAnchorId + }); + } + }) +} + +export const getInputNumber = (nodeId) => { + const data = lf.getGraphData(); + let flag = false + data.edges.forEach(item => { + if (item.targetNodeId === nodeId) { + flag = true + } + }); + if (flag) { + const arr = [] + data.nodes.forEach(item => { + if (item.properties.inputParams) { + item.properties.inputParams.forEach(item => { + if (item.type === 'number') { + arr.push(item) + } + }) + } + }) + return arr + } + return flag +} + +export const removeSwitchEdge = (nodeId, sourceAnchorId) => { + const { edges } = lf.getGraphData(); + const edge = edges.find(item => { + return item.sourceNodeId === nodeId && item.sourceAnchorId === sourceAnchorId + }) + + if (edge) { + lf.deleteEdge(edge.id); + } +} + +export const convertToTree = (data) => { + // 创建 id 到节点的映射 + const nodeMap = new Map(); + data.forEach(node => { + nodeMap.set(node.id, { ...node, name: node.properties.name || '' }); // 浅拷贝节点 + }); + + // 标记非根节点(被其他节点引用的节点) + const nonRootIds = new Set(); + data.forEach(node => { + if (node.children) { + node.children.forEach(childId => { + nonRootIds.add(childId); + }); + } + }); + + // 构建树形结构 + const result = []; + data.forEach(node => { + // 只处理根节点(未被引用的节点) + if (!nonRootIds.has(node.id)) { + const rootNode = nodeMap.get(node.id); + // 递归处理子节点 + const processNode = (currentNode) => { + if (currentNode.children) { + currentNode.children = currentNode.children.map(childId => { + const childNode = nodeMap.get(childId); + processNode(childNode); // 递归处理子节点 + return childNode; + }); + } + return currentNode; + }; + + result.push(processNode(rootNode)); + } + }); + + return result; } \ No newline at end of file diff --git a/src/views/flow/config.js b/src/views/flow/config.js index 6b55502..3026dad 100644 --- a/src/views/flow/config.js +++ b/src/views/flow/config.js @@ -1,274 +1,276 @@ -import { Group, SelectionSelect } from "@logicflow/extension"; -import { registerCommon } from "./nodes/common/index"; - -import { registerFunction } from './nodes/function' - -import cameraSvg from './icon/camera.svg' -import videoSvg from './icon/video.svg' -import loopSvg from './icon/loop.svg' -import stopLoopSvg from './icon/stopLoop.svg' -import switchSvg from './icon/switch.svg' -import startSvg from './icon/start.svg' -import endSvg from './icon/end.svg' -import microphoneSvg from './icon/microphone.svg' -import sleepSvg from './icon/sleep.svg' - -import { v4 as randomUUID } from 'uuid' - -import { useFlowStore } from "@/store/modules/flow"; - -const flowStore = useFlowStore(); - - -export const lfConfig = { - idGenerator: () => { - // 生成标准UUID并移除连字符 - // return crypto.randomUUID().replace(/-/g, ''); - return randomUUID().replace(/-/g, '') - }, - background: { - backgroundColor: "#f6f8fa", - }, - grid: false, - plugins: [Group, SelectionSelect], - animation: true, - adjustEdgeStartAndEnd: false, - // multipleSelectKey: "ctrl", - // disabledTools: ["multipleSelect"], - partial: true, - // group: { - // foldable: true, // 启用折叠功能 - // foldSize: 30, // 折叠后显示的图标尺寸 - // }, - edgeType: "bezier", - style: { - anchor: { - show: true, // 强制全局锚点显示 - hoverOn: false, - visibility: "visible", - fill: "#FF5722", // 实心绿色 - stroke: "#FF5722", // 边框同色 - strokeWidth: 0, // 消除边框 - r: 7, // 锚点半径 - hover: { fill: "#FF5722" }, // 禁用悬停变色 - }, - anchorLine: { - stroke: "#FF5722", - strokeWidth: 2, - strokeDasharray: "3,2", - }, - bezier: { - stroke: "#FF5722", - strokeWidth: 2, - arrow: false, // 关闭箭头显示 - animation: true, // 开启动画效果 - animationSpeed: 3, - }, - }, -}; - -// 注册自定义节点 -export const registerCustomizeNode = (lf) => { - registerCommon(lf) - registerFunction(lf) -}; - -const deviceOptions = () => { - return ['cam1', 'cam2', 'cam3', 'cam4'] -} - -const audioOptions = () => { - return ['spk1'] -} - -export const collapseList = [ - { - collapseTitle: "相机", - nodeList: [ - { - icon: cameraSvg, - name: "开启相机", - type: "serviceNode", - desc: "在获取相机照片时,需要先启动相机", - action: 'CAMERA_START', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'json' - }, - { - icon: cameraSvg, - name: "获取图片", - type: "serviceNode", - desc: "获取相机拍摄的照片", - action: 'CAMERA_GETRGBIMAGE', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'img', - outputParams: [{ name: 'imageUrl', type: 'Array', desc: '图片地址数组'}] - }, - { - icon: cameraSvg, - name: "关闭相机", - type: "serviceNode", - desc: "获取相机照片后,关闭该相机", - action: 'CAMERA_STOP', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'json' - }, - ], - }, - { - collapseTitle: "录像", - nodeList: [ - { - icon: videoSvg, - name: "开启录像", - type: "serviceNode", - desc: "开启摄像头,并开始录像", - action: 'CAMERA_RECORDING_START', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'json' - }, - { - icon: videoSvg, - name: "结束录像", - type: "serviceNode", - desc: "停止录像,并关闭摄像头", - action: 'CAMERA_RECORDING_STOP', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'video', - outputParams: [{ name: 'videoUrl', type: 'Array', desc: '视频播放地址数组'}] - } - ], - }, - { - collapseTitle: "功能", - nodeList: [ - { - icon: loopSvg, - name: "循环", - type: "loop", - action: 'START_LOOP', - desc: "实现对列表对象循环执行一系列任务", - }, - { - icon: stopLoopSvg, - name: "结束循环", - type: "stopLoop", - action: 'STOP_LOOP', - desc: "用于立即终止当前所在的循环,跳出循环体", - }, - { - icon: startSvg, - name: "单次循环开始", - type: "subStart", - action: 'SUB_START', - desc: "循环体内部工作流的开始节点,开始循环体内部的单次流程", - }, - { - icon: endSvg, - name: "单次循环结束", - type: "subEnd", - action: 'SUB_END', - desc: "循环体内部工作流的终止节点,结束循环体内部的单次流程", - }, - { - icon: switchSvg, - name: "分支", - type: "branch", - action: 'BRANCH', - desc: "连接多个下游分支,根据设定的条件按照顺序查找的方式来匹配运行的分支,如果匹配到某条件则只运行该条件对应的分支,否则继续匹配下一条件直至结束", - }, - { - icon: sleepSvg, - name: "睡眠", - type: "sleep", - desc: "用于睡眠整个流程,表示延迟多少毫秒", - action: 'sleep', - nodeParams: [ - { name: "delayMs", type: "input", componentType: 'number', input: "", disabled: true } - ], - outputType: 'json' - }, - ], - }, - { - collapseTitle: "机器人", - nodeList: [ - { - icon: videoSvg, - name: "机械臂", - type: "serviceNode", - desc: "控制机器人的手臂", - action: 'ALM', - nodeParams: [ - { name: "deviceId", type: "input", input: "", disabled: true } - ], - outputType: 'json' - }, - ], - }, - { - collapseTitle: "音频", - nodeList: [ - { - icon: microphoneSvg, - name: "启动麦克风", - type: "serviceNode", - desc: "用于启动麦克风的节点", - action: 'MICROPHONE_START', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'json' - }, - { - icon: microphoneSvg, - name: "停止麦克风", - type: "serviceNode", - desc: "用于停止麦克风的节点", - action: 'MICROPHONE_START', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } - ], - outputType: 'json' - }, - { - icon: microphoneSvg, - name: "播放音频", - type: "serviceNode", - desc: "用于播放音频的节点", - action: 'SPEAKER_PLAYAUDIO', - nodeParams: [ - { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: audioOptions(), disabled: true } - ], - outputType: 'json' - }, - ], - }, - { - collapseTitle: "大模型", - nodeList: [ - { - icon: microphoneSvg, - name: "获取触控坐标", - type: "serviceNode", - desc: "用于获取触控坐标的节点", - action: 'TOUCH_COORDINATES', - nodeParams: [ - { name: "words", type: "input", input: "", disabled: true } - ], - outputType: 'json', - outputParams: [{ name: 'coordinates', type: 'Object', desc: '坐标对象'}] - }, - ], - }, -] +import { Group, SelectionSelect } from "@logicflow/extension"; +import { registerCommon } from "./nodes/common/index"; + +import { registerFunction } from './nodes/function' + +import cameraSvg from './icon/camera.svg' +import videoSvg from './icon/video.svg' +import loopSvg from './icon/loop.svg' +import stopLoopSvg from './icon/stopLoop.svg' +import switchSvg from './icon/switch.svg' +import startSvg from './icon/start.svg' +import endSvg from './icon/end.svg' +import microphoneSvg from './icon/microphone.svg' +import sleepSvg from './icon/sleep.svg' + +import { v4 as randomUUID } from 'uuid' + +import { useFlowStore } from "@/store/modules/flow"; + +const flowStore = useFlowStore(); + + +export const lfConfig = { + idGenerator: () => { + // 生成标准UUID并移除连字符 + // return crypto.randomUUID().replace(/-/g, ''); + return randomUUID().replace(/-/g, '') + }, + background: { + backgroundColor: "#f6f8fa", + }, + grid: false, + plugins: [Group, SelectionSelect], + animation: true, + adjustEdgeStartAndEnd: false, + // multipleSelectKey: "ctrl", + // disabledTools: ["multipleSelect"], + partial: true, + // group: { + // foldable: true, // 启用折叠功能 + // foldSize: 30, // 折叠后显示的图标尺寸 + // }, + edgeType: "bezier", + style: { + anchor: { + show: true, // 强制全局锚点显示 + hoverOn: false, + visibility: "visible", + fill: "#FF5722", // 实心绿色 + stroke: "#FF5722", // 边框同色 + strokeWidth: 0, // 消除边框 + r: 7, // 锚点半径 + hover: { fill: "#FF5722" }, // 禁用悬停变色 + }, + anchorLine: { + stroke: "#FF5722", + strokeWidth: 2, + strokeDasharray: "3,2", + }, + bezier: { + stroke: "#FF5722", + strokeWidth: 2, + arrow: false, // 关闭箭头显示 + animation: true, // 开启动画效果 + animationSpeed: 3, + }, + }, +}; + +// 注册自定义节点 +export const registerCustomizeNode = (lf) => { + registerCommon(lf) + registerFunction(lf) +}; + +const deviceOptions = () => { + return ['cam1', 'cam2', 'cam3', 'cam4'] +} + +const audioOptions = () => { + return ['spk1'] +} + +export const collapseList = [ + { + collapseTitle: "相机", + nodeList: [ + { + icon: cameraSvg, + name: "开启相机", + type: "serviceNode", + desc: "在获取相机照片时,需要先启动相机", + action: 'CAMERA_START', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'json' + }, + { + icon: cameraSvg, + name: "获取图片", + type: "serviceNode", + desc: "获取相机拍摄的照片", + action: 'CAMERA_GETRGBIMAGE', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'img', + outputParams: [{ name: 'imageUrl', type: 'Array', desc: '图片地址数组'}] + }, + { + icon: cameraSvg, + name: "关闭相机", + type: "serviceNode", + desc: "获取相机照片后,关闭该相机", + action: 'CAMERA_STOP', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'json' + }, + ], + }, + { + collapseTitle: "录像", + nodeList: [ + { + icon: videoSvg, + name: "开启录像", + type: "serviceNode", + desc: "开启摄像头,并开始录像", + action: 'CAMERA_RECORDING_START', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'json' + }, + { + icon: videoSvg, + name: "结束录像", + type: "serviceNode", + desc: "停止录像,并关闭摄像头", + action: 'CAMERA_RECORDING_STOP', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'video', + outputParams: [{ name: 'videoUrl', type: 'Array', desc: '视频播放地址数组'}] + } + ], + }, + { + collapseTitle: "功能", + nodeList: [ + { + icon: loopSvg, + name: "循环", + type: "loop", + action: 'START_LOOP', + desc: "实现对列表对象循环执行一系列任务", + }, + { + icon: stopLoopSvg, + name: "结束循环", + type: "stopLoop", + action: 'STOP_LOOP', + desc: "用于立即终止当前所在的循环,跳出循环体", + }, + { + icon: startSvg, + name: "单次循环开始", + type: "subStart", + action: 'SUB_START', + desc: "循环体内部工作流的开始节点,开始循环体内部的单次流程", + }, + { + icon: endSvg, + name: "单次循环结束", + type: "subEnd", + action: 'SUB_END', + desc: "循环体内部工作流的终止节点,结束循环体内部的单次流程", + }, + { + icon: switchSvg, + name: "分支", + type: "branch", + action: 'BRANCH', + desc: "连接多个下游分支,根据设定的条件按照顺序查找的方式来匹配运行的分支,如果匹配到某条件则只运行该条件对应的分支,否则继续匹配下一条件直至结束", + }, + { + icon: sleepSvg, + name: "睡眠", + type: "sleep", + desc: "用于睡眠整个流程,表示延迟多少毫秒", + action: 'sleep', + nodeParams: [ + { name: "delayMs", type: "input", componentType: 'number', input: "", disabled: true } + ], + outputType: 'json' + }, + ], + }, + { + collapseTitle: "机器人", + nodeList: [ + { + icon: videoSvg, + name: "机械臂", + type: "serviceNode", + desc: "控制机器人的手臂", + action: 'ALM', + nodeParams: [ + { name: "deviceId", type: "input", input: "", disabled: true } + ], + outputType: 'json' + }, + ], + }, + { + collapseTitle: "音频", + nodeList: [ + { + icon: microphoneSvg, + name: "启动麦克风", + type: "serviceNode", + desc: "用于启动麦克风的节点", + action: 'MICROPHONE_START', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'json' + }, + { + icon: microphoneSvg, + name: "停止麦克风", + type: "serviceNode", + desc: "用于停止麦克风的节点", + action: 'MICROPHONE_START', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true } + ], + outputType: 'json' + }, + { + icon: microphoneSvg, + name: "播放音频", + type: "serviceNode", + desc: "用于播放音频的节点", + action: 'SPEAKER_PLAYAUDIO', + nodeParams: [ + { name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: audioOptions(), disabled: true } + ], + outputType: 'json' + }, + ], + }, + { + collapseTitle: "大模型", + nodeList: [ + { + icon: microphoneSvg, + name: "获取触控坐标", + type: "serviceNode", + desc: "用于获取触控坐标的节点", + action: 'TOUCH_COORDINATES', + nodeParams: [ + { name: "targetFeature", type: "input", input: "运动模式", disabled: true }, + { name: "manufacturer", type: "input", input: "xiaomi", disabled: true }, + { name: "vehType", type: "input", input: "su7", disabled: true }, + ], + outputType: 'json', + outputParams: [{ name: 'coordinates', type: 'Object', desc: '坐标对象'}] + }, + ], + }, +] diff --git a/src/views/flow/index.vue b/src/views/flow/index.vue index 86b4c04..c0541a3 100644 --- a/src/views/flow/index.vue +++ b/src/views/flow/index.vue @@ -1,692 +1,692 @@ - - - - + + + + diff --git a/src/views/flow/nodes/function/loop.vue b/src/views/flow/nodes/function/loop.vue index f12df82..a94c087 100644 --- a/src/views/flow/nodes/function/loop.vue +++ b/src/views/flow/nodes/function/loop.vue @@ -1,201 +1,200 @@ - - - \ No newline at end of file diff --git a/src/views/vi/corpus/awaken/index.vue b/src/views/vi/corpus/awaken/index.vue new file mode 100644 index 0000000..1538ee3 --- /dev/null +++ b/src/views/vi/corpus/awaken/index.vue @@ -0,0 +1,322 @@ + + + diff --git a/src/views/vi/corpus/test/index.vue b/src/views/vi/corpus/test/index.vue new file mode 100644 index 0000000..4ab2845 --- /dev/null +++ b/src/views/vi/corpus/test/index.vue @@ -0,0 +1,335 @@ + + + diff --git a/vite.config.js b/vite.config.js index 2befd7a..9bddf63 100644 --- a/vite.config.js +++ b/vite.config.js @@ -32,11 +32,11 @@ export default defineConfig(({mode, command}) => { proxy: { // https://cn.vitejs.dev/config/#server-proxy '/dev-api': { - //杨 http://10.148.108.95:13080 + //杨 http://192.168.0.10:13080 //赵 http://10.148.108.58:13080 // dev http://10.148.20.34:13080 // target: command === 'build' ? VITE_API_URL : 'http://10.148.20.34:13080', - target: command === 'build' ? VITE_API_URL : 'http://127.0.0.1:13080', + target: command === 'build' ? VITE_API_URL : 'http://192.168.0.10:13080', changeOrigin: true, rewrite: (p) => p.replace(/^\/dev-api/, '') }