Vue3中使用LogicFlow实现简单流程图
实现结果
实现功能:
- 拖拽创建节点
- 自定义节点/边
- 自定义快捷键
- 人员选择弹窗
- 右侧动态配置组件
- 配置项获取/回显
- 必填项验证
自定义节点与拖拽创建节点
拖拽节点面板node-panel.vue
<template><div class="node-panel"><divv-for="(item, key) in state.nodePanel":key="key"class="approve-node"@mousedown="dragNode(item)"><div class="node-shape" :class="'node-' + item.type"></div><div class="node-label">{{ item.text }}</div></div></div>
</template><script lang="ts" setup>
import { ILogicFlowNodePanelItem } from "@/types/logic-flow";
import LogicFlow from "@logicflow/core";
import { reactive } from "vue";
const props = defineProps<{ lf?: LogicFlow }>();
const state = reactive({nodePanel: [{type: "approver",text: "用户活动",},{type: "link",text: "连接点",},{type: "review",text: "传阅",},],
});
const dragNode = (item: ILogicFlowNodePanelItem) => {props.lf?.dnd.startDrag({type: item.type,text: item.text,});
};
</script>
自定义节点/边index.ts
/*** @description 注册节点* @export* @param {LogicFlow} lf* @return {*}*/
export function registeNode(lf: ShallowRef<LogicFlow | undefined>) {/*** @description 自定义开始节点*/class StartNode extends CircleNode {getShape() {const { x, y } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("circle", {...style,cx: x,cy: y,r: 30,stroke: "#000",fill: "#000",}),]);}getText() {const { x, y, text } = this.props.model;return h("text",{x: x,y: y,fill: "#fff",textAnchor: "middle",alignmentBaseline: "middle",style: { fontSize: 12 },},text.value);}}class StartNodeModel extends CircleNodeModel {setAttributes() {this.r = 30;this.isSelected = false;}getConnectedTargetRules() {const rules = super.getConnectedTargetRules();const geteWayOnlyAsTarget = {message: "开始节点只能连出,不能连入!",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (target) {isValid = false;}return isValid;},};rules.push(geteWayOnlyAsTarget);return rules;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const onlyOneOutEdge = {message: "开始节点只能连出一条线!",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (source?.outgoing.edges.length) {isValid = false;}return isValid;},};rules.push(onlyOneOutEdge);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "start",view: StartNode,model: StartNodeModel,});/*** @description 自定义发起节点*/class LaunchNode extends RectNode {getShape() {const { x, y, width, height, radius } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("rect", {...style,x: x - width / 2,y: y - height / 2,rx: radius,ry: radius,width: 120,height: 50,stroke: "#000",fill: "#000",}),]);}getText() {const { x, y, text, width, height } = this.props.model;return h("foreignObject",{x: x - width / 2,y: y - height / 2,className: "foreign-object",style: {width: width,height: height,},},[h("p",{style: {fontSize: 12,width: width,height: height,lineHeight: height + "px",whiteSpace: "nowrap",overflow: "hidden",textOverflow: "ellipsis",textAlign: "center",padding: "0 8px",boxSizing: "border-box",margin: "0",color: "#fff",},},text.value),]);}}class LaunchModel extends RectNodeModel {setAttributes() {this.width = 120;this.height = 50;this.radius = 4;this.isSelected = false;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const notAsTarget = {message: "不能连接自己",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (source?.id === target?.id) {isValid = false;}return isValid;},};rules.push(notAsTarget);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "launch",view: LaunchNode,model: LaunchModel,});/*** @description 自定义审批节点*/class ApproverNode extends RectNode {getShape() {const { x, y, width, height, radius } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("rect", {...style,x: x - width / 2,y: y - height / 2,rx: radius,ry: radius,width: 120,height: 50,stroke: "#facd91",fill: "#facd91",}),]);}getText() {const { x, y, text, width, height } = this.props.model;return h("foreignObject",{x: x - width / 2,y: y - height / 2,className: "foreign-object",style: {width: width,height: height,},},[h("p",{style: {fontSize: 12,width: width,height: height,lineHeight: height + "px",whiteSpace: "nowrap",overflow: "hidden",textOverflow: "ellipsis",textAlign: "center",padding: "0 8px",boxSizing: "border-box",margin: "0",},},text.value),]);}}class ApproverModel extends RectNodeModel {setAttributes() {this.width = 120;this.height = 50;this.radius = 4;this.isSelected = false;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const notAsTarget = {message: "不能连接自己",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (source?.id === target?.id) {isValid = false;}return isValid;},};rules.push(notAsTarget);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "approver",view: ApproverNode,model: ApproverModel,});/*** @description 自定义连接点节点*/class LinkNode extends RectNode {getShape() {const { x, y, width, height, radius } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("rect", {...style,x: x - width / 2,y: y - height / 2,rx: radius,ry: radius,width: 120,height: 50,stroke: "#caf982",fill: "#caf982",}),]);}getText() {const { x, y, text, width, height } = this.props.model;return h("foreignObject",{x: x - width / 2,y: y - height / 2,className: "foreign-object",style: {width: width,height: height,},},[h("p",{style: {fontSize: 12,width: width,height: height,lineHeight: height + "px",whiteSpace: "nowrap",overflow: "hidden",textOverflow: "ellipsis",textAlign: "center",padding: "0 8px",boxSizing: "border-box",margin: "0",},},text.value),]);}}class LinkModel extends RectNodeModel {setAttributes() {this.width = 120;this.height = 50;this.radius = 4;this.isSelected = false;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const notAsTarget = {message: "不能连接自己",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (source?.id === target?.id) {isValid = false;}return isValid;},};rules.push(notAsTarget);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "link",view: LinkNode,model: LinkModel,});/*** @description 自定义传阅节点*/class ReviewNode extends RectNode {getShape() {const { x, y, width, height, radius } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("rect", {...style,x: x - width / 2,y: y - height / 2,rx: radius,ry: radius,width: 120,height: 50,stroke: "#81d3f8",fill: "#81d3f8",}),]);}getText() {const { x, y, text, width, height } = this.props.model;return h("foreignObject",{x: x - width / 2,y: y - height / 2,className: "foreign-object",style: {width: width,height: height,},},[h("p",{style: {fontSize: 12,width: width,height: height,lineHeight: height + "px",whiteSpace: "nowrap",overflow: "hidden",textOverflow: "ellipsis",textAlign: "center",padding: "0 8px",boxSizing: "border-box",margin: "0",},},text.value),]);}}class ReviewModel extends RectNodeModel {setAttributes() {this.width = 120;this.height = 50;this.radius = 4;this.isSelected = false;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const notAsTarget = {message: "不能连接自己",validate: (source?: BaseNodeModel, target?: BaseNodeModel) => {let isValid = true;if (source?.id === target?.id) {isValid = false;}return isValid;},};rules.push(notAsTarget);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "review",view: ReviewNode,model: ReviewModel,});/*** @description 结束节点*/class FinishNode extends CircleNode {getShape() {const { x, y } = this.props.model;const style = this.props.model.getNodeStyle();return h("g", {}, [h("circle", {...style,cx: x,cy: y,r: 30,stroke: "#000",fill: "#000",}),]);}getText() {const { x, y, text } = this.props.model;return h("text",{x: x,y: y,fill: "#fff",textAnchor: "middle",alignmentBaseline: "middle",style: { fontSize: 12 },},text.value);}}class FinishModel extends CircleNodeModel {setAttributes() {this.r = 30;this.isSelected = false;}getConnectedSourceRules() {const rules = super.getConnectedSourceRules();const notAsTarget = {message: "终止节点不能作为连线的起点",validate: () => false,};rules.push(notAsTarget);return rules;}createId() {return uuidv4();}}lf.value?.register({type: "end",view: FinishNode,model: FinishModel,});/*** @description 虚线*/class DashedLineModel extends PolylineEdgeModel {getEdgeStyle() {const style = super.getEdgeStyle();style.stroke = "#000";style.strokeDasharray = "3 3";return style;}}lf.value?.register({type: "dashedLine",view: PolylineEdge,model: DashedLineModel,});/*** @description 开始的连线*/class StartPolylineModel extends PolylineEdgeModel {setAttributes() {this.isSelected = false;this.isHitable = false;}}lf.value?.register({type: "startPolyline",view: PolylineEdge,model: StartPolylineModel,});
}
注册logicflow并使用自定义节点
<template><div class="logic-flow-container"><div class="logic-flow-header"><el-button type="primary" @click="getData">获取数据</el-button><el-button type="primary" @click="submit">提交</el-button></div><div class="logic-flow-main"><div class="logic-flow" ref="logicFlowRef"></div><Settingclass="logic-flow-setting":data="nodeData!":lf="lf":type="state.settingType"></Setting><NodePanel :lf="lf"></NodePanel></div><!-- 当lf有值 才能注册事件 --><Control v-if="lf" :lf="lf"></Control></div>
</template><script lang="ts">
export default { name: "LogicFlow" };
</script>
<script lang="ts" setup>
import LogicFlow from "@logicflow/core";
import "@logicflow/core/lib/style/index.css";
import "@logicflow/extension/lib/style/index.css";
import { onMounted, reactive, ref, ShallowRef, shallowRef } from "vue";
import NodePanel from "./components/node-panel.vue";
import { registeNode, registerKeyboard, requiredConfig } from "./index";
import { ElMessage } from "element-plus";
import Control from "./components/control.vue";
import Setting from "./components/setting.vue";
import { SettingType } from "@/types/logic-flow";const logicFlowRef = ref<HTMLDivElement>();
const nodeData = ref<LogicFlow.NodeData | LogicFlow.EdgeData>(); // 节点数据
const state = reactive({settingType: "all" as SettingType,
});
const lf = shallowRef<LogicFlow>();const getSettingInfo = (data: LogicFlow.NodeData | LogicFlow.EdgeData) => {switch (data.type) {case "launch":nodeData.value = data;state.settingType = data.type;break;case "approver":nodeData.value = data;state.settingType = data.type;break;case "link":nodeData.value = data;state.settingType = data.type;break;case "review":nodeData.value = data;state.settingType = data.type;break;case "polyline":case "dashedLine":nodeData.value = data;state.settingType = data.type;break;}
};
/*** @description 注册事件*/
const initEvent = (lf: ShallowRef<LogicFlow | undefined>) => {lf.value?.on("blank:click", (e) => {state.settingType = "all";});lf.value?.on("node:mousedown", ({ data }) => {lf.value?.selectElementById(data.id, false);getSettingInfo(data);});lf.value?.on("edge:click", ({ data }) => {lf.value?.selectElementById(data.id, false);getSettingInfo(data);});lf.value?.on("connection:not-allowed", (data) => {ElMessage.error(data.msg);return false;});lf.value?.on("node:dnd-add", ({ data }) => {// 选中节点 更改信息lf.value?.selectElementById(data.id, false);getSettingInfo(data);lf.value?.container.focus(); // 聚焦 能够使用键盘操作});
};
/*** @description 获取数据*/
const getData = () => {console.log(lf.value?.getGraphData());
};
/*** @description 提交 验证数据*/
const submit = () => {const { nodes } = lf.value?.getGraphData() as LogicFlow.GraphData;for (let index = 0; index < nodes.length; index++) {const data = nodes[index];const { properties } = data;// 循环配置项for (const key in properties) {// 数组配置项 判断是否为空if (Array.isArray(properties[key])) {if (requiredConfig[key] && properties[key].length === 0) {return ElMessage.error(`${data.text?.value}节点 ${requiredConfig[key]}`);}} else {// 非数组配置项 判断是否为空if (requiredConfig[key] && !properties[key]) {return ElMessage.error(`${data.text?.value}节点 ${requiredConfig[key]}`);}}}}console.log(lf.value?.getGraphData());
};onMounted(() => {lf.value = new LogicFlow({container: logicFlowRef.value!,grid: true,keyboard: {enabled: true,shortcuts: registerKeyboard(lf, nodeData),},textEdit: false,});registeNode(lf);initEvent(lf);lf.value.render({nodes: [{id: "node_1",type: "start",x: 100,y: 300,properties: {width: 60,height: 60,},text: {x: 100,y: 300,value: "开始",},},{id: "node_2",type: "launch",x: 100,y: 400,properties: {width: 120,height: 50,},text: {x: 100,y: 400,value: "发起流程",},},{id: "node_3",type: "end",x: 100,y: 600,properties: {width: 60,height: 60,},text: {x: 100,y: 600,value: "结束",},},],edges: [{id: "edge_1",type: "startPolyline",sourceNodeId: "node_1",targetNodeId: "node_2",},{id: "edge_2",type: "polyline",sourceNodeId: "node_2",targetNodeId: "node_3",},],});lf.value.translateCenter(); // 将图形移动到画布中央
});
</script>
右侧的配置设置
- 通过
componentIs
实现不同的配置组件 - 通过logicflow的
setProperties()
函数,将配置项注入节点/边的properties
对象中,目的是传参和回显的时候方便
人员选择组件
正选、反选、回显,可作为一个单独组件使用,目前使用的是el-tree
,数据量大时可考虑虚拟树
<template><MyDialogv-model="state.visible"title="选择人员"width="800px"@close="close"@cancel="close"@submit="submit"><div class="type"><label><span>发起人:</span><el-radio-group v-model="state.type"><el-radio value="1">指定人员</el-radio><el-radio value="2">角色</el-radio></el-radio-group></label></div><div class="panel"><div class="left-panel"><div class="panel-title">人员选择</div><div class="search"><el-inputv-model="state.filterText"style="width: 100%"placeholder="请输入筛选内容"/></div><div class="content"><el-treeref="treeRef":data="state.data"show-checkboxnode-key="key":check-on-click-node="true":filter-node-method="filterNode"@check-change="checkChange"/></div></div><div class="right-panel"><div class="panel-title">已选择</div><div class="content checked-content"><el-tagv-for="tag in state.checkedList":key="tag.key"closabletype="primary"@close="handleClose(tag.key)">{{ tag.label }}</el-tag></div></div></div></MyDialog>
</template><script lang="ts">
export default { name: "ChoosePerson" };
</script>
<script lang="ts" setup>
import { ElTree } from "element-plus";
import { nextTick, reactive, ref, watch } from "vue";
interface Tree {[key: string]: any;
}
const state = reactive({visible: false,type: "1",filterText: "",value: [],data: [{label: "张三",key: "1",},{label: "李四",key: "2",},{label: "王五",key: "3",children: [{label: "王五1",key: "31",},{label: "王五2",key: "32",},],},],checked: [] as string[],checkedList: [] as { label: string; key: string }[],
});
const treeRef = ref<InstanceType<typeof ElTree>>();
const emits = defineEmits(["submit"]);
/*** @description 筛选节点*/
watch(() => state.filterText,(val) => {treeRef.value!.filter(val);}
);
const open = (checked: string[]) => {state.visible = true;nextTick(() => {state.checked = checked;treeRef.value?.setCheckedKeys([...checked], false);});
};
const close = () => {state.visible = false;state.filterText = "";
};
const submit = () => {emits("submit", state.checked, state.checkedList);close();
};
/*** @description 筛选节点*/
const filterNode = (value: string, data: Tree) => {if (!value) return true;return data.label.includes(value);
};
/*** @description 选中节点*/
const checkChange = () => {// 已选的id string[] 用来提交state.checked = treeRef.value?.getCheckedNodes(true, false).map((item) => item.key) as string[];// 已选的对象 {label: string; key: string}[] 用来展示tagstate.checkedList = treeRef.value?.getCheckedNodes(true, false).map((item) => {return {label: item.label,key: item.key,};})!;
};
/*** @description 删除已选人员*/
const handleClose = (key: string) => {state.checkedList = state.checkedList.filter((item) => item.key !== key);treeRef.value?.setCheckedKeys(state.checkedList.map((item) => item.key),false);
};
/*** @description 清空已选人员*/
const clear = () => {state.checkedList = [];state.checked = [];treeRef.value?.setCheckedKeys([], false);
};
defineExpose({open,clear,
});
</script><style lang="scss" scoped>
.type {display: flex;align-items: center;margin-bottom: 20px;span {margin-right: 10px;}label {display: flex;align-items: center;}
}
.panel {width: 100%;display: flex;.left-panel {flex: 1;border: 1px solid #ccc;border-radius: 4px;.search {padding: 6px 10px;}}.right-panel {flex: 1;margin-left: 20px;border: 1px solid #ccc;border-radius: 4px;}.panel-title {padding: 10px 0;font-size: 14px;font-weight: bold;background-color: #f5f5f5;text-align: center;}.content {max-height: 400px;min-height: 200px;overflow: auto;}.checked-content {padding: 6px 10px;.el-tag + .el-tag {margin-left: 10px;}}
}
</style>
自定义快捷键,根据源码改编
/*** @description 注册键盘事件* @export* @param {(ShallowRef<LogicFlow | undefined>)} lf* @param {(Ref<LogicFlow.NodeData | LogicFlow.EdgeData | undefined>)} nodeData* @return {*}*/
export function registerKeyboard(lf: ShallowRef<LogicFlow | undefined>,nodeData: Ref<LogicFlow.NodeData | LogicFlow.EdgeData | undefined>
) {let copyNodes = undefined as LogicFlow.NodeData[] | undefined;let TRANSLATION_DISTANCE = 40;let CHILDREN_TRANSLATION_DISTANCE = 40;const cv = [{keys: ["ctrl + c", "cmd + c"],callback: () => {copyNodes = lf.value?.getSelectElements().nodes;},},{keys: ["ctrl + v", "cmd + v"],callback: () => {const startOrEndNode = copyNodes?.find((node) =>node.type === "start" ||node.type === "end" ||node.type === "launch");if (startOrEndNode) {return true;}if (copyNodes) {lf.value?.clearSelectElements();copyNodes.forEach(function (node) {node.x += TRANSLATION_DISTANCE;node.y += TRANSLATION_DISTANCE;node.text!.x += TRANSLATION_DISTANCE;node.text!.y += TRANSLATION_DISTANCE;return node;});let addElements = lf.value?.addElements({ nodes: copyNodes, edges: [] },CHILDREN_TRANSLATION_DISTANCE);if (!addElements) return true;addElements.nodes.forEach(function (node) {nodeData.value = node.getData();return lf.value?.selectElementById(node.id, true);});CHILDREN_TRANSLATION_DISTANCE =CHILDREN_TRANSLATION_DISTANCE + TRANSLATION_DISTANCE;}return false;},},{keys: ["backspace"],callback: () => {const elements = lf.value?.getSelectElements(true);if (elements) {lf.value?.clearSelectElements();elements.edges.forEach(function (edge) {return edge.id && lf.value?.deleteEdge(edge.id);});elements.nodes.forEach(function (node) {if (node.type === "start" ||node.type === "end" ||node.type === "launch") {return true;}return node.id && lf.value?.deleteNode(node.id);});return false;}},},];return cv;
}
仓库地址
在线预览
相关文章:

Vue3中使用LogicFlow实现简单流程图
实现结果 实现功能: 拖拽创建节点自定义节点/边自定义快捷键人员选择弹窗右侧动态配置组件配置项获取/回显必填项验证 自定义节点与拖拽创建节点 拖拽节点面板node-panel.vue <template><div class"node-panel"><divv-for"(item, k…...

《重学Java设计模式》之 工厂方法模式
《重学Java设计模式》之 建造者模式 《重学Java设计模式》之 原型模式 《重学Java设计模式》之 单例模式 模拟发奖多种商品 工程结构 奖品发放接口 package com.yys.mes.design.factory.store;public interface ICommodity {/*** Author Sherry* Date 14:20 2024/11/6**/voi…...

【大数据学习 | kafka】kafka的数据存储结构
以上是kafka的数据的存储方式。 这些数据可以在服务器集群上对应的文件夹中查看到。 [hexuanhadoop106 __consumer_offsets-0]$ ll 总用量 8 -rw-rw-r--. 1 hexuan hexuan 10485760 10月 28 22:21 00000000000000000000.index -rw-rw-r--. 1 hexuan hexuan 0 10月 28 …...

知识竞赛答题系统,线上答题小程序链接怎么做?
随着智能手机的普及,越来越多的单位开始在线上开展知识竞赛。这种形式的知识竞赛不仅易于操作,而且参与度更高。那么线上知识竞赛答题系统怎么做呢?自己可以做吗?答案是可以的!借助微信答题系统制作平台风传吧…...

基于SSM的社区物业管理系统+LW参考示例
1.项目介绍 系统角色:管理员、业主(普通用户)功能模块:管理员(用户管理、二手置换管理、报修管理、缴费管理、公告管理)、普通用户(登录注册、二手置换、生活缴费、信息采集、报事报修…...
android——jetpack startup初始化框架
一、jetpack startup Android Jetpack Startup是一个库,它简化了Android应用启动过程,尤其是对于那些需要处理复杂数据绑定和初始化逻辑的应用。它的核心在于提供了一个StartupComponent,用于声明应用的初始化逻辑,这个逻辑会在首…...
英伟达HOVER——用于人形机器人的多功能全身控制器:整合不同的控制模式且实现彼此之间的无缝切换
前言 前几天,一在长沙的朋友李总发我一个英伟达HOVER的视频(自从我今年年初以来持续不断的解读各大顶级实验室的最前沿paper、以及分享我司七月在具身领域的探索与落地后,影响力便越来越大了,不断加油 ),该视频说的有点玄乎&…...
GEE代码学习 day17
13.2 地球上到处都有许多图像吗? 我们可以使用下面的代码将这个 reducer count 应用于我们过滤后的 ImageCollection。我们将返回相同的数据集并筛选 2020 年,但没有地理限制。这将收集来自世界各地的图像,然后计算每个像素中的图像数量。以…...

论文阅读笔记-Covariate Shift: A Review and Analysis on Classifiers
前言 标题:Covariate Shift: A Review and Analysis on Classifiers 原文链接:Link\ 我们都知道在机器学习模型中,训练数据和测试数据是不同的阶段,并且,通常是是假定训练数据和测试数据点遵循相同的分布。但是实际上&…...

基于SSM+VUE守护萌宠宠物网站JAVA|VUE|Springboot计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解
源代码数据库LW文档(1万字以上)开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统:Window操作系统 2、开发工具:IntelliJ IDEA或者Eclipse 3、数据库存储:…...

【在Linux世界中追寻伟大的One Piece】Socket编程TCP
目录 1 -> TCP socket API 2 -> V1 -Echo Server 2.1 -> 测试多个连接的情况 1 -> TCP socket API socket(): socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符。应用程序可以像读写文件一样用r…...
进入半导体行业需要具备哪些能力?
要进入半导体公司,尤其是从事工艺流程设计和制程优化的岗位,需要具备一定的跨学科背景。 以某公司招聘要求为例: **公司 招聘岗位:工艺工程师 该公司是一家从事半导体设备、工艺与材料研发、生产和销售的公司,面向…...

Nature重磅:AI化学家再升级!大幅提升实验效率,推动化学合成进入“智能化”新阶段
人工智能(AI)驱动的机器人,正在我们的生活中扮演着越来越重要的角色,而在化学合成实验室内,它们也在悄然改变着传统实验方式。 如今,科学家们在智能化学领域取得了新突破—— 来自英国利物浦大学的研究团…...

源代码泄漏怎么办?SDC沙盒成为破局利器
在数字化时代,源代码安全已成为企业关注的焦点。源代码的泄露不仅可能导致知识产权的损失,还可能被竞争对手利用,给企业带来巨大的经济损失和法律风险。因此,采取有效的源代码防泄漏措施至关重要。深信达的SDC沙盒防泄密软件&…...

【论文复现】基于图卷积网络的轻量化推荐模型
本文所涉及所有资源均在这里可获取。 📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步,喜爱音乐、摄影的一位博主。 📗本文收录于论文复现系列,大家有兴趣的可以看一看…...

使用ssh-key免密登录服务器或免密连接git代码仓库网站
ssh登录服务器场景 假设有两台机器,分别是: 源机器:主机A(hostA),ip:198.168.0.1 目标机器:主机B(hostB),ip:192.168.0.2 ssh-key免…...

自由学习记录(19)
unity核心也算是看完了吧,但觉得的确是少了点东西,之后再看mvc框架,和网络开发,,感觉有必要想想主次顺序了,毕竟在明年的3月之前尽量让自己更有贴合需求的能力 先了解一些相关概念,不用看懂&am…...

Elasticsearch中时间字段格式用法详解
Elasticsearch中时间字段格式用法详解 攻城狮Jozz关注IP属地: 北京 2024.03.18 16:27:51字数 758阅读 2,571 Elasticsearch(简称ES)是一个基于Lucene构建的开源、分布式、RESTful搜索引擎。它提供了全文搜索、结构化搜索以及分析等功能,广泛…...

蓝桥杯-网络安全比赛题目-遗漏的压缩包
小蓝同学给你发来了他自己开发的网站链接, 他说他故意留下了一个压缩包文件,里面有网站的源代码, 他想考验一下你的网络安全技能。 (点击“下发赛题”后,你将得到一个http链接。如果该链接自动跳转到https,…...

ES海量数据插入如何优化性能?
2024年10月NJSD技术盛典暨第十届NJSD软件开发者大会、第八届IAS互联网架构大会在南京召开。百度文心快码总经理臧志分享了《AI原生研发新范式的实践与思考》,探讨了大模型赋能下的研发变革及如何在公司和行业中落地,AI原生研发新范式的内涵和推动经验。 …...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...