O2OA开发平台前端源码级二次开发(Vue3,React)

在使用O2OA进行项目定制化开发时,我们可以开发新的前端组件(x_component)以扩展O2OA来实现更多的业务。这种新增前端组件或者前端业务的开发通常会配合后端自定义应用实现的服务来完成系统内数据的交互。在当系统默认的界面不符合系统UI/UE设计需要,希望重新设计现有功能的前端展现时,我们也需要新增或者修改原有的组件源码。

上述要求我们除了使用O2OA平台的门户页面设计达到目标,针对于复杂的前端交互设计,开发属于自己的x_component也是一个有效的方式。

本文主要介绍几种前端二次开发的方式,以及与流行前端框架(Vue、React)的集成。

先决条件

  1. 获取到O2OA的源码,参照前面的课程所介绍的内容。

  2. 有一台运行的O2OA服务器,作为开发服务器。

  3. 开发机安装了Node.js环境,版本要求16及以上版本。

  4. 为了方便开发,最好有您熟悉的前端开发IDE工具,如WebStorm 或 VSCode。但这并不是强制的。本文后续的操作,我们以VSCode为例。

用VSCode打开O2OA的源码目录,并打开终端,输入以下命令:

npm install -g @o2oa/component-tools

image (15).png

image (15).png

此命令全局安装了@o2oa/component-tools,用于创建O2OAcomponent。建议每次需要创建component时运行此命令,以获取最新的更新。

然后进入o2web/source目录,然后运行npm install。

cd o2web/source

npm install

执行完成后,就可以创建component了。

o2oa原生方式的component

创建component组件

创建component的命令格式是:o2-cmpt create name ,其中的“name”就是要创建的component名称。如创建一个名为“custom.homepage”的component。

o2-cmpt create custom.homepage

image (16).png

运行后需要选择使用什么框架模式来创建component,目前支持两种方式:vue3、o2oa原生方式。(对于其它框架如react或者Angular的集成可以查询官方文档,有比较详细的步骤和说明。)

现在我们先介绍o2oa原生方式。选择“o2_native”然后回车,看到以下界面,就说明创建成功了。

image (17).png

此时就可以在目录列表中看到“x_component_custom_homepage”这个目录了。

image (18).png

展开目录后,看到文件结构是:

$Main/目录:存放静态文件资源,包括图标、css、html模板文件等

lp/目录:存放国际化语言包,zh-cn.js、en.js

Main.js:component入口js文件。

如果在运行命令时,使用的是windowss的PowerShell,可能会报错“…… 因为在此系统上禁止运行脚本……”的错误,有两个办法解决:1、用管理员权限打开Windows PowerShell,运行 set-executionpolicy remotesigned 命令,然后先择 Y ,回车即可运行脚本;2、是切换到Command,如下图:

image (19).png

部署组件

前端的打包部署使用了gulp,为了能快速部署组件到开发服务器,需要增加一个配置文件:o2web/gulpconfig.js,用于设置部署到服务器的信息。

内容如下:

module.exports = {
    "dev": {	//"dev"为配置名称
        'upload': 'sftp',	//sftp, ftp, 或 local
        'location': 'E:/o2server/servers/webServer/',	//本地服务器部署路径,仅upload为local时有效
        'host': 'px.o2oa.net',	//sftp或ftp时的服务器地址
        'user': 'root',					//sftp或ftp 的登录用户
        'pass': '********',	//sftp或ftp 登录用户的密码
        "port": 22,					//sftp或ftp 的端口
        "remotePath": "/data/o2server/servers/webServer/",	//sftp或ftp 的服务器部署路径
        "dest": "dest"	//打包后生成的本地路径
    }
};

上面的这个配置表示,如果在打包时传入"dev"作为参数的话,会自动打包,并通过sftp部署到px.o2oa.net服务器的“/data/o2server/servers/webServer/”路径下,这就是正在运行开发服务器的web路径,所以当我们部署上去后,就可以在开发服务器直接运行component了。

配置完成后,就可以运行打包部署脚本了:

gulp x_component_custom_homepage --ev dev

如果不出意外,运行正确后,出现下面的信息:

image (20).png

此时我们新创建的component就部署到开发服务器上了。

运行组件

然后就可以访问开发服务器查看custom.homepage的运行情况,有三种方法:

1、通过浏览器打开:http://hostaname/x_desktop/index.html?app=custom.homepage

2、通过浏览器打开:http://hostaname/x_desktop/app.html?app=custom.homepage

以上两种方法中的“hostname”替换为开发服务器地址。

3、通过浏览器打开:http://hostaname/x_desktop/index.html,然后用管理员身份登录,打开主菜单-系统设置

image (21).png

进入应用后选择“系统部署”,点击最后的“部署组件”:

image (22).png

然后填入合适的信息

image (23).png

组件名称:可随意填写,但不能与已有组件重名

组件标题:可随意填写,此信息其实已经无效,实际的组件标题会自动获取component的语言包的title数据。

组件路径:这个必须和我们创建组件时的名称一致,这个例子中,就是“custom.homepage”

组件图标:会自动获取component组件目录下的appicon.png

是否可见:表示此组件是否会在主菜单中出现。

可访问列表:可以选择个人、群组和角色,设定此组件只有哪些人可访问,为空时表示不限制,

拒绝访问列表:可以选择个人、群组和角色,设定此组件哪些人不可访问,为空时表示不限制,

当“可访问列表”和“拒绝访问列表”都为空时,表示所有人都可以访问。

填写好信息后,点击“部署组件”。

然后就可以在主菜单中看到这个组件了,点击就可以打开它。

image (24).png

打开后组件页面是这个样子的:

image (25).png

这个就是默认的O2OAcomponent组件,它主要实现了列示当前用户最新的5个待办,以及打开日程安排、打开组织管理,启动流程等样例功能。

组件源码介绍

在组件源码目录下的$Main/下存放了静态资源文件,几个主要文件如下:

appicon.png:作为组件在平台主菜单中显示的图标

default/style.css:组件使用的css文件,此文件的css内容仅对当前组件生效

lp/目录存放语言包文件,包含了zh-cn.js和en.js,其中的title就是组件显示的标题。

Main.js文件是组件的入口,它定义了一个类,我们简单介绍一下主要的方法和参数:

//这一行定义了custom.homepage组件是否可以在平台中打开多个窗口
MWF.xApplication.custom.homepage.options.multitask = false;

//此处定义了MWF.xApplication.custom.homepage.Main类,组件被打开时,会实例化这个类
MWF.xApplication.custom.homepage.Main = new Class({
  
  //它继承了MWF.xApplication.Common.Main类,这是系统定义的所有组件的基类
	Extends: MWF.xApplication.Common.Main,
  
	Implements: [Options, Events],

	options: {
		"style1": "default",
    //此处定义了组件使用的默认样式,它对应$Main/default目录,系统会自动加载对应目录的css和资源
		"style": "default",
		"name": "custom.homepage",	//组件的名称
		"mvcStyle": "style.css",	//要加载的css文件名
		"icon": "icon.png",				//图标的文件名
		"title": MWF.xApplication.custom.homepage.LP.title	//组件的标题,从lp/目录下的语言包获取
	},
  //此方法在组件被加载之前运行,此处只是赋值了语言信息
	onQueryLoad: function(){
		this.lp = MWF.xApplication.custom.homepage.LP;
	},
  
  //loadApplication是组件对象加载的入口方法,在此处为组件创建dom对象
  //一个最简单的组件,只需要实现此方法即可。它是组件中唯一一个必须要实现的方法
  //组件的this.conent是一个div容器,它是组件的容器对象,组件的所有dom元素都应该被this.conent包裹
	loadApplication: function(callback){
		var url = this.path+this.options.style+"/view.html";
		this.content.loadHtml(url, {"bind": {"lp": this.lp}, "module": this}, function(){
			this.loadTaskView();
		}.bind(this));
	},
  
  //---------------------------------------------------------------------
  //之后所有的方法都是当前组件特有的方法,这需要根据组件的功能自行添加
  
	loadTaskView: function(){
		o2.Actions.load("x_processplatform_assemble_surface").TaskAction.listMyPaging(1,5, function(json){
			debugger;
			this.taskListView.loadHtml(this.path+this.options.style+"/taskView.html", {"bind": {"lp": this.lp, "data": json.data}, "module": this}, function(){
				this.doSomething();
			}.bind(this));
		}.bind(this));
	},
	doSomething: function(){

	},
  //通过o2.api获取平台api运行环境,然后可以在api文档钟查询具体方法和对象的使用方法
	openTask: function(id, e, data){
		o2.api.page.openWork(id);
	},
	openCalendar: function(){
		o2.api.page.openApplication("Calendar");
	},
	openOrganization: function(){
		o2.api.page.openApplication("Org");
	},
	openInBrowser: function() {
		this.openInNewBrowser(true);
	},
	startProcess: function(){
		o2.api.page.startProcess();
	},
	createDocument: function(){
		o2.api.page.createDocument();
	}
});

接着来看一下 loadApplication 方法做了什么

loadApplication: function(callback){
  //先计算view.html的路径
  var url = this.path+this.options.style+"/view.html";
  
  //然后通过dom对象的loadHtml方法,将view.html的内容,渲染到this.content中。
  //在 view.html 内容被加载完成后,通过回调方法,调用loadTaskView方法。
  //loadHtml是O2OA为dom对象的一个扩展方法,它实现了一个简单的模板引擎。
  //第一个参数是要加载的html模板的url
  //第二个参数是options对象,其中bind是要绑定到模板的json格式数据,此处我们就是绑定了语言信息
  //		                    module是html中的元素要绑定到的组件。
  //第三个参数是加载完成后的回调函数。
  this.content.loadHtml(url, {"bind": {"lp": this.lp}, "module": this}, function(){
    this.loadTaskView();
  }.bind(this));
},

那就需要看一下view.html的内容了:

<div class="hello">
    <img class="logo" alt="O2OA logo" src="../x_component_Empty/$Main/default/icons/o2logo.png">
    <h1>{{ $.lp.welcome }}</h1>
    <p>
        For more O2OA development document,<br>
        check out the
        <a href="https://www.o2oa.net/develop.html" target="_blank" rel="noopener">O2OA develop documentation</a>.
    </p>

    <div class="task" data-o2-element="taskListView"></div>
</div>

其中的{{$.xxx}}的内容引用了绑定过来的bind信息。“$”就是绑定的数据(前面所说的bind的数据)。

其中data-o2-element属性是给这个dom对象一个名称,这样我们就可以在组件脚本中,通过this.[名称]获取到这个dom对象了。这个例子中,就是this.taskListView 了。

在view.html加载完成后,会执行 this.loadTaskView方法,那我们就详细看看这个方法

loadTaskView: function(){
  //o2.Actions对象的load方法可以载入指定上下文的后端服务,并将其转换为前端可调用的方法
  //所有的平台restful api,都可以通过http://develop.o2oa.net/x_program_center来查看
  //这里载入了x_processplatform_assemble_surface服务,此服务定义了与流程相关的一组restful api
  //TaskAction.listMyPaging方法用于获取当前用户的待办列表
  //第一个参数是获取待办的页码;第二个参数是每页获取几条待办;第三个参数的是获取成功的回调函数 
  o2.Actions.load("x_processplatform_assemble_surface").TaskAction.listMyPaging(1,5, function(json){
    //成功回调后,调用 this.taskListView.loadHtml方法,这里的this.taskListView就是上述view.html
    //中data-o2-element属性为“taskListView”的div元素。
    //通过loadHtml方法载入了taskView.html,并绑定json.data,json.data就是获取的待办列表对象数组
    this.taskListView.loadHtml(this.path+this.options.style+"/taskView.html", {"bind": {"lp": this.lp, "data": json.data}, "module": this}, function(){
      //载入taskView.html后,可以做一些其他事情...
      this.doSomething();
    }.bind(this));
  }.bind(this));
}

再来看看 taskView.html

<h3>{{$.lp.taskListTitle}}</h3>
<br>
<table align="center" class="taskListTable" border="1">
    <tr>
        <th>{{$.lp.taskTitle}}</th>
        <th>{{$.lp.taskProcess}}</th>
        <th>{{$.lp.taskTime}}</th>
    </tr>

    {{each $.data}}
    <tr>
        <td><a href="#" data-o2-events="click:openTask:{{$.work}}">{{$.title}}</a></td>
        <td>{{$.processName}}</td>
        <td>{{$.startTime}}</td>
    </tr>
    {{end each}}
</table>
<br>
<button data-o2-events="click:openCalendar">{{$.lp.openCalendar}}</button>
<button data-o2-events="click:openOrganization">{{$.lp.openOrganization}}</button>
<button data-o2-events="click:startProcess">{{$.lp.startProcess}}</button>
<br>
<button data-o2-events="click:openInBrowser">{{$.lp.openInBrowser}}</button>

这里有一个 {{each $.data}} 和 {{end each}},这代表循环$.data数据,并处理内部的html内容。$.data必须是一个可迭代的数据。

data-o2-events自定义属性用于绑定事件,属性值中,如果有多个事件绑定,使用分号“;”分隔,每个事件绑定的格式为:“事件名:方法:[参数1]:[参数2]...”,在loadHtml时,将component组件绑定到了“module”属性,所以这里的“方法”需要在component组件中定义。如: data-o2-events="click:openCalendar",在Main.js中就定义了这一个方法,用于打开日程安排组件。

openCalendar: function(){
  layout.openApplication(null, "Calendar");
}

组件修改

接着来修改组件内容,一般情况首先要修改的是组件标题,所以我们打开语言包,修改title内容:

//zh-cn.js
MWF.xApplication.custom.homepage.LP = {
	"title": "我的主页",
	"welcome": "Welcome to O2OA Component",
	"taskListTitle": "此处列出您的5个最新待办",

	"taskTitle": "标题",
	"taskProcess": "流程",
	"taskTime": "到达时间",

	"openCalendar": "打开日程管理",
	"openOrganization": "打开组织管理",
	"startProcess": "启动流程",
	"openInBrowser": "在新浏览器窗口中打开"
};


//en.js
MWF.xApplication.custom.homepage.LP = {
	"title": "MyHomepage",
	"welcome": "Welcome to O2OA Component",
	"taskListTitle": "Here are your top 5 task",

	"taskTitle": "Title",
	"taskProcess": "Process",
	"taskTime": "Time",

	"openCalendar": "Open Calendar",
	"openOrganization": "Open Organization",
	"startProcess": "Start Process",
	"openInBrowser": "Open In Browser"
};

保存后,再次运行部署命令:

gulp x_component_custom_homepage --ev dev

image (26).png

运行完成后在刷新浏览器就可以看到修改后的效果了。

每次修改后运行部署命令,是令人不愉快的,所以我们可以运行以下命令,来监听文件变化,并自动部署:

gulp watch --src x_component_custom_homepage --ev dev

之后每次修改组件的任何文件时,就会自动部署到开发环境“dev”了。

至此,native类型的component的框架搭建好了。

vue3类型的component

O2OA支持使用vue3创建component

创建组件

我们再次打开终端,到o2web/source目录,运行创建component命令,创建一个名为“custom.workplace”的component。

o2-cmpt create custom.workplace

然后选择“vue3”,会自动创建基于vue3的component。在安装完部分依赖之后,会询问几个问题:

1、需要输入开发服务器的hosts

2、需要输入开发服务器的center服务端口,默认是80

3、需要输入开发服务器的web服务端口,默认是80

4、确认开发服务器是否使用https,默认为 否(N)

其中开发服务器我们使用 px.o2oa.net, 其他选项都保持默认即可。

看到以下界面,说明component创建完成。

image (27).png

然后选择“vue3”,会自动创建基于vue3的component。在安装完部分依赖之后,会询问几个问题:

1、需要输入开发服务器的hosts

2、需要输入开发服务器的center服务端口,默认是80

3、需要输入开发服务器的web服务端口,默认是80

4、确认开发服务器是否使用https,默认为 否(N)

其中开发服务器我们使用 px.o2oa.net, 其他选项都保持默认即可。

看到以下界面,说明component创建完成。

image (28).png

此时就可以在目录列表中看到“x_component_custom_workplace”这个目录了。

image (29).png

展开目录后,就可以看到一个标准的vue应用的文件结构。其中有o2.config.js文件内容如下:

module.exports = {
    "server": {
        "host": "develop.o2oa.net",
        "port": "80",
        "httpPort": "80",
        "https": false
    }
}

这里的内容就是在创建component时询问的四个问题答案,它主要用于在启动本地开发服务器时,确定要连接的后端服务地址。我们可以随时修改这个配置,来连接不同的O2OA开发服务器。

在看到public/$Main/和public/lp/目录,这和原生component的$Main目录和lp目录内容完全一致。

运行组件

vue类型的component,是可以运行在本地开发服务器上的,所以我们只需要在组件目录下运行npm run serve即可

cd x_component_custom_workplace

npm run serve

运行后,会启动本地开发服务器,并自动打开浏览器,访问。

image (30).png

image (31).png

image (31).png

添加路由插件
我们还可以为vue component添加vue router插件,这和所有vue应用一样,可以通过vue ui添加,也可以使用命令:vue add router.

Shell复制代码

1

vue add router

image (32).png

如果有源码有未提交的commit,会提示,建议先提交后再安装插件。这里我们选择y,继续安装。

安装一些依赖包后,会询问是否使用histroy模式,此处我们选择 n ,使用 hash 模式。

image (33).png

接着安装完成,我们可以看到src目录下,增加了router/index.js和view/目录下的两个视图。

重新启动本地开发服务器:npm run serve,可以在浏览器中看到效果:

image (34).png

修改组件

此时再修改组件内容,如修改src/components/O2Task.vue文件,中的create()方法,将获取5个待办,改获取10个待办:

...
<script>
  ...

  created(){
  	//此处将第二个参数从5改为10
    o2.Actions.load("x_processplatform_assemble_surface").TaskAction.V2ListPaging(1, 10, null).then((json)=>{
      this.$data.taskList = json.data;
    });
  }

...
</script>
...

保存文件后,本地服务器会自动编译,浏览器会自动体现修改的内容。

image (35).png

image (35).png

这样我们就可以方便的开发component组件了。

集成自定义应用

部署组件

此时组件都是在本地服务器运行,要部署到服务器的方法和native类型的组件是一样的。在确保存在了gulpconfig.js文件,并正确配置后,在o2web/目录下运行gulp命令:

gulp x_component_custom_workplace --ev dev

就可以将组件部署到服务器了。

可以和native组件一样的方式,访问custom.workplace组件了。

React类型的component

O2OA支持使用React创建component组件,其方法与Vue3的组件非常类似。

创建组件

我们再次打开终端,到o2web/source目录,运行创建component命令,创建一个名为“custom.liveplace”的component。

o2-cmpt create custom.liveplace

image (36).png

然后选择“react”,就会自动创建基于React的component。在安装完部分依赖之后,同样会询问几个问题:

1、需要输入开发服务器的hosts

2、需要输入开发服务器的center服务端口,默认是80

3、需要输入开发服务器的web服务端口,默认是80

4、确认开发服务器是否使用https,默认为 否(N)

其中开发服务器我们使用 px.o2oa.net, 其他选项都保持默认即可。

image (37).png

看到以下界面,说明component创建完成。(React应用创建过程较长,需要耐心等待一下)

image (39).png

此时就可以在目录列表中看到“x_component_custom_liveplace”这个目录了。

image (40).png

展开目录后,就可以看到一个标准的React应用的文件结构。其中有o2.config.js文件内容如下:

module.exports = {
    "server": {
        "host": "develop.o2oa.net",
        "port": "80",
        "httpPort": "80",
        "https": false
    }
}

这里的内容就是在创建component时询问的四个问题答案,它主要用于在启动本地开发服务器时,确定要连接的后端服务地址。我们可以随时修改这个配置,来连接不同的O2OA开发服务器。

再看到public/$Main/和public/lp/目录,这和原生component的$Main目录和lp目录内容完全一致。

运行组件

React类型的component,是可以运行在本地开发服务器上的,所以我们只需要在组件目录下运行npm run start即可

cd x_component_custom_liveplace

npm run start

运行后,会启动本地开发服务器,并自动打开浏览器,访问。

image (41).png

image (42).png

此时可以修改组件源码,这里我们先修改一下欢迎信息。

修改中文语言信息:打开组件源码目录的public/lp/zh-cn.js,修改一下welcome:

MWF.xApplication.custom.liveplace.LP = {
    "title": "custom.liveplace",

    "welcome": "欢迎使用O2OA和React!",
    "taskListTitle": "此处列出您的5个最新待办",

    "taskTitle": "标题",
    "taskProcess": "流程",
    "taskTime": "到达时间",

    "openCalendar": "打开日程管理",
    "openOrganization": "打开组织管理",
    "startProcess": "启动流程",
    "createDocument": "创建信息",
    "openInBrowser": "在新浏览器窗口中打开"
}

刷新浏览器窗口后,就可以看到:

image (43).png

我们可以切换语言信息,来看一下,点击右上角的个人头像,点击“个人设置”,将“语言设置”改为“English”,“保存个人信息”后,刷新页面。

image (44).png

就可以看到,组件的语言信息,已经切换过来了:

image (45).png

接着就需要根据需求的内容,进行组件开发了。

部署组件

部署React类型的组件,也非常容易。和上述两种模式是一样的。

在确保存在了gulpconfig.js文件,并正确配置后,在o2web/目录下运行gulp命令:

gulp x_component_custom_liveplace --ev dev

就可以将组件部署到服务器了。

可以和native组件一样的方式,访问custom.liveplace组件了。

总结

  本文我们讲述了如何对O2OA进行前端的二次开发,介绍了创建O2OA component的方式,包括原生方式、基于Vue3的方式和基于React的方式。各种O2OA component脚手架工具帮助开发者更方便地搭建了O2OA组件的开发框架。无论那种方式,都完整的保留了O2OA平台的所有可用API,认证体系,多语言特性、后端服务方法转换等特性,使开发者可以更好地专注于需要实现的业务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/586962.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

283. 移动零 11. 盛最多水的容器

283. 移动零 把非零的数全交换到前面去 11. 盛最多水的容器 双指针&#xff1a; 双指针一个在头 一个在尾部 计算两个边的盛水量并更新数值 左右两边 哪边矮就移动哪边

区块链快速参考(三)

原文&#xff1a;zh.annas-archive.org/md5/b5e57485b0609afbfba46ff759c5d264 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十七章&#xff1a;去中心化应用程序 去中心化应用&#xff08;DApps&#xff09;是在去中心化网络上运行的应用程序&#xff0c;不受集…

2024五一杯数学建模B题思路分析 - 未来新城背景下的交通需求规划与可达率问题

文章目录 1 赛题选题分析 2 解题思路详细的思路过程放在文档中 ! ! &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;3 最新思路更新 1 赛题 B题 未来新城背景下的交通需求规划与可达率问题 随着城市化的持续发展&#xff0c;交通规划在新兴城市建设中显得尤为关…

Linux搭建靶场

提前准备&#xff1a; 文章中所使用到的Linux系统&#xff1a;Ubantu20.4sqlilabs靶场下载地址&#xff1a;GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based. 一. 安装phpstudy phpstudy安装命令&#xff1a;wget -O install.sh h…

Map和Set基础

目录 一、导论 二、Map 三、Set 本文找先不涉及两种数据结构的底层&#xff0c;目标是&#xff1a; 理解Map和Set的大体框架&#xff0c;了解他们有什么用&#xff0c;用在哪里的&#xff0c;然后再从浅层深入底层。 小编认为&#xff1a; 先了解也下Map和Set大体是用来做…

Mysql--创建数据库

一、创建一个数据库 “db_classes” mysql> create database db_classes; mysql> show databases; -------------------- | Database | -------------------- | db_classes | | information_schema | | mysql | | performance_schema | |…

开通Jetbrains个人账号,赠送这些付费插件

开通Jetbrains个人账号&#xff0c;或者Jetbrains现成账号的, 可赠送以下付费插件 现成账号&#xff1a;https://web.52shizhan.cn/activity/xqt8ly 个人账号&#xff1a;https://web.52shizhan.cn/legal 账号支持全家桶系列&#xff1a;AppCode,CLion,DataGrip,GoLand,Intell…

Codeforces Round 941 (Div. 2) (A~D)

1966A - Card Exchange 题意&#xff1a; 思路&#xff1a;手玩一下发现当存在某个数字个数超过k个&#xff0c;那么就能一直操作下去。那么答案就是k-1. void solve() {cin >> n >> m;map<int,int>mp;int maxx 1;for(int i 0 ; i < n ; i ){int x;c…

手把手教数据结构与算法:优先级队列(银行排队问题)

队列 基本概念 队列的定义 队列&#xff08;Queue&#xff09;&#xff1a;队列是一种常见的数据结构&#xff0c;遵循先进先出&#xff08;First-In-First-Out, FIFO&#xff09;的原则。在队列中&#xff0c;元素按照进入队列的顺序排列。队列是一个线性的数据结构&#x…

深入解析yolov5,为什么算法都是基于yolov5做改进的?(一)

YOLOv5简介 YOLOv5是一种单阶段目标检测算法&#xff0c;它在YOLOv4的基础上引入了多项改进&#xff0c;显著提升了检测的速度和精度。YOLOv5的设计哲学是简洁高效&#xff0c;它有四个版本&#xff1a;YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x&#xff0c;分别对应不同的模型大小…

深度学习从入门到精通——词向量介绍及应用

词向量介绍 词向量&#xff08;Word embedding&#xff09;&#xff0c;即把词语表示成实数向量。“好”的词向量能体现词语直接的相近关系。词向量已经被证明可以提高NLP任务的性能&#xff0c;例如语法分析和情感分析。词向量与词嵌入技术的提出是为了解决onehot的缺陷。它把…

pytorch中创建maskrcnn模型

0.模型输入/输出参数参见 链接: pytorch的mask-rcnn的模型参数解释 核心代码 GeneralizedRCNN(这里以mask-rcnn来解释说明) # 通过输入图像获取fpn特征图,注意这里的backbone不是直接的resnet,而是fpn化后的 features self.backbone(images.tensors) # 由于是mask-rcnn,故而…

如何快速搭建nginx服务

华子目录 nginx简介概念特点nginx框架nginx关键工作机制 nginx正向代理功能nginx反向代理功能nginx反向代理的工作流程代理本质 nginx负载均衡部署nginx常用命令systemctl系列nginx自带命令 nginx配置文件主配置文件/etc/nginx/nginx.conf内容结构模块分析配置分析注意示例 ngi…

Android创建快捷方式到桌面

效果图 参考 https://blog.51cto.com/u_16175498/8811197https://blog.51cto.com/u_16175498/8811197 权限 <uses-permission android:name"com.android.launcher.permission.INSTALL_SHORTCUT" /> 实现 if (Build.VERSION.SDK_INT > Build.VERSION_C…

【已解决】Python Selenium chromedriver Pycharm闪退的问题

概要 根据不同的业务场景需求&#xff0c;有时我们难免会使用程序来打开浏览器进行访问。本文在pycharm中使用selenium打开chromedriver出现闪退问题&#xff0c;根据不断尝试&#xff0c;最终找到的问题根本是版本问题。 代码如下 # (1) 导入selenium from selenium import …

C++ stack、queue以及deque

1、stack和queue常用接口 严格来说栈和队列的实现是容器适配器 1、常用接口&#xff1a; 栈&#xff1a;top、push、pop、size、emptystack - C Reference (cplusplus.com) 队列&#xff1a;top、push、pop、swap、size、emptyqueue - C Reference (cplusplus.com) 2、deque&a…

Android手势识别面试问题及回答

问题 1: 如何在Android中实现基本的手势识别&#xff1f; 答案: 在Android中&#xff0c;可以通过使用GestureDetector类来实现基本的手势识别。首先需要创建一个GestureDetector的实例&#xff0c;并实现GestureDetector.OnGestureListener接口来响应各种手势事件&#xff0c…

ubuntu安装mysql时候修改root密码

前情&#xff1a; 使用set password for rootlocalhost ‘passwd’&#xff1b; set password for ‘root’‘localhost’‘passwd’&#xff1b; update user set passwordpassword(‘passwd’) where user‘root’ and host ‘localhost’; flush privileges; 以上方法均报…

定制开发AI智能名片商城小程序:玩转积分制度的成功案例

在数字化浪潮席卷而来的今天&#xff0c;企业营销方式不断创新&#xff0c;力求在众多竞争对手中脱颖而出。其中&#xff0c;积分制度以其直观、有效的特点&#xff0c;成为了众多企业的营销利器。某时尚品牌“潮流前线”便是其中的佼佼者。他们通过定制一款AI智能名片商城小程…

德国著名自动化公司Festo设计了一款仿生蜜蜂,仅重34g,支持多只蜜蜂编队飞行!...

德国著名的气动元件研发及自动化解决方案供应商Festo公司近日展示了一款仿生蜜蜂&#xff08;BionicBee&#xff09;&#xff0c;重量只有34g&#xff0c;却完全可以实现自主飞行&#xff0c;还支持多只相同的蜜蜂机器人编队飞行。 BionicBee 重约 34 克&#xff0c;长 22 厘米…