LogicFlow 学习笔记——1. 初步使用 LogicFlow
什么是 LogicFlow
LogicFlow 是一个开源的前端流程图编辑器和工作流引擎,旨在帮助开发者和业务人员在网页端创建、编辑和管理复杂的业务流程和工作流。它提供了一个直观的界面和强大的功能,使得设计和管理工作流变得更加高效和便捷。
官网地址:https://site.logic-flow.cn/tutorial
LogicFlow 的主要功能
- 可视化编辑: 提供拖拽式的节点和连线操作,用户可以通过简单的鼠标操作设计和调整流程图。
- 节点和边的自定义: 支持自定义节点和边的样式、行为和属性,满足不同业务场景的需求。
- 插件系统: 提供丰富的插件机制,可以根据需要扩展 LogicFlow 的功能,例如增加特定类型的节点或边。
- 数据导入导出: 支持将流程图数据导出为 JSON 格式,便于保存和共享,同时也支持从 JSON 数据导入流程图。
- 事件机制: 提供丰富的事件机制,可以监听节点、边的添加、删除、修改等操作,方便与其他系统进行集成。
- 嵌入式使用: 可以嵌入到任何前端应用中,支持 React、Vue 等主流前端框架。
更多有关 LogicFlow 文章:https://site.logic-flow.cn/article/article01
新建前端项目编写 LogicFlow Demo
为了方便和系统化地学习 LogicFlow,这里我们将新建一个前端项目来编写对应的样例代码。我们选择使用 Vite + Vue + TypeScript 的技术栈来构建前端项目。
Vite 官网:https://www.vitejs.net/
新建前端项目
我们将创建一个使用 Vite4, Vue3, TypeScript, ES6, vue-router-next 以及 Element-Plus 的前端项目,并使用 pnpm 作为包管理器。
-
初始化项目
在终端中运行以下命令来创建一个新的项目文件夹并进入该文件夹:mkdir logicflow_example && cd logicflow_example
-
创建一个新的Vite项目
使用Vite的官方模板初始化一个新的Vue + TypeScript项目:pnpm create vite . -- --template vue-ts
命令行中选择 VUE 和 TypeScript,如下图所示:
-
安装 Vue Router 和 Element-Plus 以及安装 Node.js 类型定义文件
安装最新版本的vue-router-next和Element-Plus:pnpm add vue-router@4 element-plus
安装Node.js类型定义文件
pnpm add -D @types/node
-
配置路径别名
在 Vite 项目中配置路径别名,以便使用 ‘@’ 符号来代替相对路径,从而简化模块导入。修改 vite.config.ts 文件,设置别名让 ‘@’ 指向 src 文件夹的步骤如下:a. 打开或创建 Vite 配置文件
如果你的项目中还没有 vite.config.ts 文件,请在项目根目录下创建这个文件。b. 编辑配置文件
在 vite.config.ts 文件中,编辑如下内容:import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path'// https://vitejs.dev/config/ export default defineConfig({plugins: [vue()],resolve: {alias: {'@': path.resolve(__dirname, './src')}} })
c. 在 tsconfig.json 文件中新增如下配置:
-
配置Vue Router
在 src 目录下新建 router 目录,并创建 index.ts 文件,代码内容如下:import { createRouter, createWebHistory } from "vue-router";const routes = [{path: "/example/logic_flow/example01",name: "LogicFlowExample01",component: () => import("@/views/Example/LogicFlow/Example01.vue"),},{path: "/example/logic_flow/example02",name: "LogicFlowExample02",component: () => import("@/views/Example/LogicFlow/Example02.vue"),}, ];const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes, });export default router;
-
配置 Element-Plus 和 Router
在src/main.ts中,添加Element-Plus 和 Router 的全局引用:import { createApp } from 'vue' import './style.css' import App from './App.vue' import router from '@/router' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css'const app = createApp(App) app.use(router) app.use(ElementPlus) app.mount('#app')
-
新建 Router 中配置的对应的页面
在项目中新建views/Example/LogicFlow
目录,并创建两个 Vue 文件Example01.vue
和Example02.vue
,如下所示:
文件内容可以自己随意编写,例如:<script setup lang="ts"></script> <template><h1>Example01</h1> </template>
-
修改 App.vue
修改 App.vue 内容如下:<script setup lang="ts"> </script><template><RouterView /> </template><style scoped> </style>
此时启动项目
pnpm run dev
访问前端页面http://localhost:5173/example/logic_flow/example01
会出现如下页面:
-
配置样式以及进行简单布局
为了方便页面的选择,这里可以使用 Element Plus 的 Menu 组件。首先需要修改style.css
中的样式:body {margin: 0;min-height: 100vh; } #app {padding: 0; }
新建
layout/AppView.vue
内容如下:<script setup lang="ts"> import { ElMenu, ElMenuItem, ElSubMenu } from 'element-plus' import { menuItems } from './config' import 'element-plus/dist/index.css' </script><template><div id="app"><ElMenustyle="height: 100vh; width: 200px"default-active="1"class="el-menu-vertical-demo"active-text-color="#ffd04b"background-color="#545c64"text-color="#fff"router><!-- 使用 v-for 和 v-if/v-else 分别处理有子菜单和无子菜单的情况 --><template v-for="item in menuItems"><!-- 当存在子菜单时,使用 ElSubMenu --><ElSubMenuv-if="item.children":key="'submenu-' + item.index":index="item.index"><template #title><i v-if="item.icon" :class="item.icon" style="margin-right: 10px" /><span>{{ item.title }}</span></template><ElMenuItemv-for="child in item.children":key="child.index":index="child.index":route="child.path">{{ child.title }}</ElMenuItem></ElSubMenu><!-- 没有子菜单时,直接显示 ElMenuItem --><ElMenuItemv-else:key="'menuitem-' + item.index":index="item.index":route="item.path"><i v-if="item.icon" :class="item.icon" style="margin-right: 10px" /><span>{{ item.title }}</span></ElMenuItem></template></ElMenu><div class="main-content"><RouterView /></div></div> </template><style> #app {display: flex;width: 100%; } .el-menu-vertical-demo {border-right: 0; } .main-content {flex-grow: 1;padding: 20px;width: 100%; } </style>
创建
layout/config/index.ts
文件内容如下:interface MenuItem {index: string;title: string;icon?: string;path?: string;children?: MenuItem[]; }export const menuItems: MenuItem[] = [{index: '1',title: 'LogicFlowExample',icon: 'fa-solid fa-desktop',children: [{index: '1-1',title: 'Example 1',path: '/example/logic_flow/example01'},{index: '1-2',title: 'Example 2',path: '/example/logic_flow/example02'}]} ];
修改
App.vue
如下所示:<script setup lang="ts"> import AppView from './layout/AppView.vue'; </script><template><AppView /> </template><style scoped></style>
-
配置 eslint
运行以下命令安装 ESLint 及其相关插件:pnpm add -D eslint prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-vue
项目中新建
.prettierrc
文件,并添加如下内容:{"semi": false,"singleQuote": true,"trailingComma": "none" }
新建
.eslintrc
文件,并添加如下内容:{// "extends" 部分用于继承一系列预定义的规则集或配置。"extends": [// "eslint:recommended": 包含 ESLint 的核心规则集,这些规则可以检测JavaScript代码中的潜在问题。"eslint:recommended",// "plugin:vue/vue3-recommended": 专为 Vue 3 设计的规则集,包含对 Vue 代码风格和最佳实践的严格检查。// 这个规则集适用于 Vue 3 项目,涵盖了 Vue 特定的语法和模式。"plugin:vue/vue3-recommended",// "plugin:prettier/recommended": 这是一个配置集,旨在集成 Prettier 的格式化功能到 ESLint 中。// 它首先使用 "eslint-plugin-prettier" 来运行 Prettier 作为 ESLint 规则,// 然后使用 "eslint-config-prettier" 来禁用所有可能与 Prettier 冲突的 ESLint 规则。"plugin:prettier/recommended"],// "rules" 部分允许你定义或重写从 "extends" 部分继承来的规则。"rules": {// "prettier/prettier": "error": 配置 Prettier 产生的问题为 ESLint 的 "error" 级别错误。// 这意味着任何代码风格不符合 Prettier 配置的地方都会被 ESLint 标记为错误,// 这样可以在编写代码时即时纠正格式问题。"prettier/prettier": "error"} }
在
.vscode
中配置settings.json
,内容如下:{"editor.formatOnSave": true,"editor.codeActionsOnSave": {"source.fixAll": "always","source.fixAll.eslint": "always"},"eslint.validate": ["javascript","vue","typescript"],"[vue]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},"[typescript]": {"editor.formatOnSave": true} }
项目启动后运行如下所示:
-
安装 Font Awesome CSS
使用 pnpm 安装 Font Awesome 的 CSS 包pnpm install @fortawesome/fontawesome-free
在
main.js
中引入// main.js 或 main.ts import '@fortawesome/fontawesome-free/css/all.min.css';
此时页面即可显示图图标:
初步使用 LogicFlow
LogicFlow 分为:
core
包——核心包extension
包——插件包(不使用插件时不需要引入)engine
包——执行引擎
- 使用 pnpm 安装 logicflow
pnpm install @logicflow/core --save
- 在 Example01.vue 中编写如下代码:
运行后页面如下所示:<script setup lang="ts"> import LogicFlow from '@logicflow/core' import '@logicflow/core/dist/style/index.css' import { onMounted } from 'vue'// 定义图表数据,包含节点和边 const data = {nodes: [{id: '1',type: 'rect', // 节点类型为矩形x: 100, // 节点的 x 坐标y: 100, // 节点的 y 坐标text: '节点1' // 节点显示的文本},{id: '2',type: 'circle', // 节点类型为圆形x: 300, // 节点的 x 坐标y: 100, // 节点的 y 坐标text: '节点2' // 节点显示的文本}],edges: [{sourceNodeId: '1', // 起始节点的 IDtargetNodeId: '2', // 目标节点的 IDtype: 'polyline', // 边的类型为折线text: '连线', // 边显示的文本startPoint: {x: 140, // 边起点的 x 坐标y: 100 // 边起点的 y 坐标},endPoint: {x: 250, // 边终点的 x 坐标y: 100 // 边终点的 y 坐标}}] }// 在组件挂载时执行 onMounted(() => {// 创建 LogicFlow 实例const lf = new LogicFlow({container: document.getElementById('container')!, // 指定容器元素grid: true // 启用网格})// 渲染图表数据lf.render(data) }) </script><template><h3>Example01</h3><div id="container"></div><!-- 用于显示 LogicFlow 图表的容器 --> </template><style> #container {/* 容器宽度 */width: 100%;/* 容器高度 */height: 500px; } </style>
LogicFlow 支持 JSON 格式数据,上面代码 data 对象中nodes
代表节点数据,edges
代表边数据
渲染节点和边
在 Example02.vue 中编写如下代码:
<script setup lang="ts">
import { LogicFlow, Definition } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'// 静默模式配置,禁用滚动、移动和缩放等功能
const SilentConfig = {isSilentMode: true, // 启用静默模式stopScrollGraph: true, // 禁止滚动图表stopMoveGraph: true, // 禁止移动图表stopZoomGraph: true, // 禁止缩放图表adjustNodePosition: true // 调整节点位置
}// 样式配置部分,定义节点和边的样式
const styleConfig: Partial<Definition> = {style: {rect: {rx: 5, // 矩形节点的圆角 x 半径ry: 5, // 矩形节点的圆角 y 半径strokeWidth: 2 // 矩形节点的边框宽度},circle: {fill: '#f5f5f5', // 圆形节点的填充颜色stroke: '#fff' // 圆形节点的边框颜色}}
}// 定义图表数据,包含节点和边
const data = {nodes: [{id: '1',type: 'rect', // 节点类型为矩形x: 100, // 节点的 x 坐标y: 100, // 节点的 y 坐标text: '节点1' // 节点显示的文本},{id: '2',type: 'circle', // 节点类型为圆形x: 300, // 节点的 x 坐标y: 100, // 节点的 y 坐标text: '节点2' // 节点显示的文本}],edges: [{sourceNodeId: '1', // 起始节点的 IDtargetNodeId: '2', // 目标节点的 IDtype: 'polyline', // 边的类型为折线text: '连线', // 边显示的文本startPoint: {x: 140, // 边起点的 x 坐标y: 100 // 边起点的 y 坐标},endPoint: {x: 250, // 边终点的 x 坐标y: 100 // 边终点的 y 坐标}}]
}// 在组件挂载时执行
onMounted(() => {// 创建 LogicFlow 实例const lf = new LogicFlow({container: document.getElementById('container')!, // 指定容器元素grid: true, // 启用网格...SilentConfig, // 应用静默模式配置...styleConfig // 应用样式配置})// 渲染图表数据lf.render(data)
})
</script><template><h3>Example02</h3><div id="container"></div><!-- 用于显示 LogicFlow 图表的容器 -->
</template><style>
#container {width: 100%; /* 容器宽度 */height: 500px; /* 容器高度 */
}
</style>
运行后页面如下:
使用前端框架节点
创建 src/views/Example/LogicFlow/component/CustomEdge
目录,在目录下新建 CustomLine.vue
文件,内容如下:
<script setup lang="ts">
// 这里可以包含 TypeScript 代码或特定逻辑
</script>
<template><div class="custom-edge">aaa</div>
</template><style scoped>
.custom-edge {flex: 1 1;text-align: center;background-color: #fff;border: 1px solid black;border-radius: 8px;
}
</style>
之后创建 src/views/Example/LogicFlow/component/CustomEdge/types/index.ts
文件,内容如下:
import { BaseEdgeModel, h, LineEdge } from '@logicflow/core'
import { createApp } from 'vue'
import CustomLine from '../CustomLine.vue'// 默认的边的宽度和高度
const DEFAULT_WIDTH = 48
const DEFAULT_HEIGHT = 32// 自定义边的模型类,继承自BaseEdgeModel
export class CustomEdgeModel extends BaseEdgeModel {// 获取边的样式,可以在这里自定义边的视觉效果getEdgeStyle() {const edgeStyle = super.getEdgeStyle()edgeStyle.strokeDasharray = '4 4' // 设置虚线样式edgeStyle.stroke = '#DDDFE3' // 设置线的颜色return edgeStyle}
}// 自定义边的视图类,继承自LineEdge
export class CustomEdgeView extends LineEdge {// 生成边的SVG元素getEdge() {const { model } = this.props // 从props中获取模型const { customWidth = DEFAULT_WIDTH, customHeight = DEFAULT_HEIGHT } =model.getProperties() // 获取自定义的宽度和高度const id = model.id // 获取模型的IDconst edgeStyle = model.getEdgeStyle() // 获取边的样式const { startPoint, endPoint, arrowConfig } = model // 获取起点、终点和箭头配置// 计算线条的SVG属性const lineData = {x1: startPoint.x,y1: startPoint.y,x2: endPoint.x,y2: endPoint.y}// 计算外部对象的位置和尺寸const positionData = {x: (startPoint.x + endPoint.x - customWidth) / 2,y: (startPoint.y + endPoint.y - customHeight) / 2,width: customWidth,height: customHeight}const wrapperStyle = {width: customWidth,height: customHeight}// 延迟挂载Vue组件到DOMsetTimeout(() => {const container = document.querySelector(`#${id}`) // 查找容器if (container) {createApp(CustomLine).mount(container) // 如果容器存在,则挂载Vue组件}}, 0)// 返回SVG元素的集合return h('g', {}, [h('line', { ...lineData, ...edgeStyle, ...arrowConfig }), // 创建线条h('foreignObject', { ...positionData }, [// 创建外部对象,用于承载Vue组件h('div', {id,style: wrapperStyle,class: 'lf-custom-edge-wrapper'})])])}// 返回追加的SVG元素,这里默认为空getAppend() {return h('g', {}, [])}
}
创建 src/views/Example/LogicFlow/component/CustomEdge/index.ts
文件内容如下:
// index.ts
import { CustomEdgeModel, CustomEdgeView } from './types'export default {type: 'CustomEdge',view: CustomEdgeView,model: CustomEdgeModel
}
创建 src/views/Example/LogicFlow/Example03.vue
文件,代码如下:
<script setup lang="ts">
import { LogicFlow, Definition } from '@logicflow/core'
import '@logicflow/core/dist/style/index.css'
import { onMounted } from 'vue'
import CustomEdge from './component/CustomEdge'// 静默模式配置,禁用滚动、移动和缩放等功能
const SilentConfig = {isSilentMode: true, // 启用静默模式stopScrollGraph: true, // 禁止滚动图表stopMoveGraph: true, // 禁止移动图表stopZoomGraph: true, // 禁止缩放图表adjustNodePosition: true // 调整节点位置
}// 样式配置部分,定义节点和边的样式
const styleConfig: Partial<Definition> = {style: {rect: {rx: 5, // 矩形节点的圆角 x 半径ry: 5, // 矩形节点的圆角 y 半径strokeWidth: 2 // 矩形节点的边框宽度},circle: {fill: '#f5f5f5', // 圆形节点的填充颜色stroke: '#fff' // 圆形节点的边框颜色}}
}// 定义图表数据,包含节点和边
const data = {nodes: [{type: 'rect',x: 100,y: 100,text: '节点1',id: 'node_id_1'},{type: 'rect',text: '节点2',x: 300,y: 100,id: 'node_id_2'}],edges: [{id: 'edge_id_1',type: 'CustomEdge',sourceNodeId: 'node_id_1',properties: {},targetNodeId: 'node_id_2',startPoint: {x: 140,y: 100},endPoint: {x: 250,y: 100}}]
}// 在组件挂载时执行
onMounted(() => {// 创建 LogicFlow 实例const lf = new LogicFlow({container: document.getElementById('container')!, // 指定容器元素grid: true, // 启用网格...SilentConfig, // 应用静默模式配置...styleConfig // 应用样式配置})lf.register(CustomEdge)// 渲染图表数据lf.render(data)lf.translateCenter()
})
</script><template><h3>Example03</h3><div id="container"></div><!-- 用于显示 LogicFlow 图表的容器 -->
</template><style>
#container {width: 100%; /* 容器宽度 */height: 500px; /* 容器高度 */
}
.lf-custom-edge-wrapper {display: flex;align-items: center;justify-content: center;
}
</style>
再配置下 Menu 和 Router,运行结果如下:
使用插件
LogicFlow 最初的目标就是支持一个扩展性强的流程绘制工具,用来满足各种业务需求。为了让LogicFlow的拓展性足够强,LogicFlow将所有的非核心功能都使用插件的方式开发,然后将这些插件放到@logicflow/extension包中。
执行命令安装插件包:
pnpm install @logicflow/extension --save
修改 Example03.vue
,新增如下内容:
import '@logicflow/extension/lib/style/index.css'
import { Control } from '@logicflow/extension'
LogicFlow.use(Control)
页面内容如下:
需要注意的是如果代码中使用 LogicFlow.use(Control)
其将注册插件到全局,也就是说如果此时访问了Example03页面,代码加载了LogicFlow.use(Control)
那么此时再访问其他页面,其他页面的 LogicFlow 实例也会加载该插件,为了不影响其他页面的实例可以注册插件到对应的实例:
const lf = new LogicFlow({container: document.getElementById('container')!, // 指定容器元素grid: true, // 启用网格...SilentConfig, // 应用静默模式配置...styleConfig, // 应用样式配置plugins: [Control] // 使用插件 注册插件到实例})
完整样例代码:https://github.com/lt5227/example_code/tree/main/logicflow_example
下一篇:LogicFlow 基础 实例
相关文章:

LogicFlow 学习笔记——1. 初步使用 LogicFlow
什么是 LogicFlow LogicFlow 是一个开源的前端流程图编辑器和工作流引擎,旨在帮助开发者和业务人员在网页端创建、编辑和管理复杂的业务流程和工作流。它提供了一个直观的界面和强大的功能,使得设计和管理工作流变得更加高效和便捷。 官网地址ÿ…...

场外个股期权通道业务是什么意思?
今天带你了解场外个股期权通道业务是什么意思?场外个股期权业务是指在沪深交易所之外进行的个股期权交易。它是一种非标准化的合约,不在交易所内进行交割。 场外个股期权通道业务,是指投资者通过与场外个股期权机构通道签订合约,购…...

分页插件结合collection标签后分页数量不准确的问题
问题1:不使用collection 聚合分页正确 简单列子 T_ATOM_DICT表有 idname1原子12原子23原子34原子45原子56原子6 T_ATOM_DICT_AUDIT_ROUTE表审核记录表有 idaudit1拒绝1通过4拒绝 我要显示那些原子审核了,我把两个表inner join 就是那些原子审核过了 idnameaudit1原子1拒绝…...
git diff 命令
目录标题 [Q&A] git diff 作用常见用法比较工作目录与暂存区比较暂存区与最近一次提交比较工作目录与最近一次提交比较两个具体的提交之间差异 [Q&A] git diff 作用 git diff 用于展示不同版本之间文件内容的变化。 常见用法 比较工作目录与暂存区 显示工作目录中尚…...
Code Review常用术语
CR: Code Review. 请求代码审查。PR: pull request. 拉取请求,给其他项目提交代码。MR: merge request. 合并请求。LGTM: Looks Good To Me.对我来说,还不错。表示认可这次PR,同意merge合并代码到远程仓库。…...
HashMap 源码中的巧妙小技巧
根据容量计算大于容量的最小的哈希表的大小(table的length),这里的length需要满足length2^n,也就是我们需要根据容量算出最小的n的值 static final int tableSizeFor(int cap) {int n cap - 1;n | n >>> 1;n | n >>> 2;n | n >&g…...

极具吸引力的小程序 UI 风格
极具吸引力的小程序 UI 风格...

数据库 | 试卷五试卷六试卷七
1. 主码不相同!相同的话就不能唯一标识非主属性了 2.从关系规范化理论的角度讲,一个只满足 1NF 的关系可能存在的四方面问题 是: 数据冗余度大,插入异常,修改异常,删除异常 3.数据模型的三大要素是什么&…...

网页五子棋对战项目测试(selenium+Junit5)
目录 网页五子棋对战项目介绍 网页五子棋对战测试的思维导图 网页五子棋对战的UI自动化测试 测试一:测试注册界面 测试二:测试登陆界面 测试三:测试游戏大厅界面 测试四:测试游戏房间界面以及观战房间界面 测试五&#…...

stable diffusion 局部重绘 reference-only api 接口调试
webUI api payload 插件生成的接口参数不准确,reference-only 的image不是对象,就是不同字符串字段,直接传,不是套image。 综上,那个插件参数不确定,应直接看插件的源码,看它接受什么参数 错误…...

浪潮信息内存故障预警技术再升级 服务器稳定性再获提升
浪潮信息近日对其内存故障智能预警修复技术进行了全面升级,再次取得技术突破。此次升级后,公司服务器的宕机率实现了80%锐降,再次彰显了浪潮信息在服务器技术领域的卓越能力。 浪潮信息全新升级服务器内存故障智能预警修复技术MUPR (Memory …...

JWT整合Gateway实现鉴权(RSA与公私密钥工具类)
一.业务流程 1.使用RSA生成公钥和私钥。私钥保存在授权中心,公钥保存在网关(gateway)和各个信任微服务中。 2.用户请求登录。 3.授权中心进行校验,通过后使用私钥对JWT进行签名加密。并将JWT返回给用户 4.用户携带JWT访问 5.gateway直接通过公钥解密JWT进…...
vue实现全屏screenfull-封装组件
1. 安装依赖 npm install --save screenfull 2. 引用 import screenfull from "screenfull" 3.封装fullScreen/index: <template><div><el-tooltip v-if"!content" effect"dark" :content"fullscreenTips" placement&…...

【LinkedList与链表】
目录 1,ArrayList的缺陷 2,链表 2.1 链表的概念及结构 2.2 链表的实现 2.2.1 无头单向非循环链表实现 3,LinkedList的模拟实现 3.1 无头双向链表实现 4,LinkedList的使用 4.1 什么是LinkedList 4.2 LinkedList的使用 5…...

为数据安全护航,袋鼠云在数据分类分级上的探索实践
在大数据时代,数据具有多源异构的特性,且价值各异,企业需依据数据的重要性、价值指数等予以区分,以利采取不同的数据保护举措,避免数据泄露。故而,数据分类分级管理属于数据安全保护中极为重要的环节之一。…...
Spring 循环依赖详解
Spring 循环依赖详解 1. 引言 在Spring框架中,依赖注入(Dependency Injection, DI)是其核心功能之一,它通过配置来管理对象的创建和它们之间的依赖关系。然而,在复杂的应用程序中,开发人员有时会遇到循环…...
项目经理真的不能太“拧巴”
前期的项目经理经常是“拧巴”的,就是心里纠结、思路混乱、行动迟缓。对于每天需要面对各种挑战、协调各方资源、确保项目顺利进行的项目经理来说,这种“拧巴”不仅会让自己陷入内耗中,还会让项目出大问题。 项目计划总是改来改去࿰…...

企业如何选择合适的CRM工具?除Salesforce之外的10大主流选择
对比salesforce,其他10款优秀CRM:纷享销客CRM、Zoho CRM、腾讯企点、销售易、企业微信 (WeCom)、Odoo CR、OroCRM、金蝶、用友CRM、EspoCRM 虽然Salesforce以其全面的功能和强大的市场占有率在海外收获了许多客户,但Salesforce在国内市场的接…...

每年1-1.2万人毕业,男女比例约3:1,测绘工程的就业率如何
测绘工程,一个让人闻风丧胆的理科专业,虎扑评分4.2: 干过测绘的,苦不苦只有大家心里知道,带大家来感受一下,兄弟们的精神状态都十分美妙: 测绘专业到底是什么情况? PS.测绘分为本科…...

JimuReport 积木报表 v1.7.6 版本发布,免费的低代码报表
项目介绍 一款免费的数据可视化报表工具,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...