本篇梳理扩展 O2OA 平台前端界面的可选路线,覆盖原生组件与 Vue、React 等框架。前置环节是全局安装组件脚手架并补齐依赖,随后用命令创建组件、选择框架模式,再填写开发服务器地址与端口。原生组件需了解静态资源、语言包与入口脚本的职责,改标题与页面时同步调整语言包和模板绑定。部署依靠打包工具与服务器配置文件完成,也可在后台登记组件路径与访问名单,注意端口占用与脚本执行策略等阻碍。
在使用 O2OA 进行项目定制化开发时,可以通过开发新的前端组件(x_component)来扩展 O2OA,实现更多业务。这种新增前端组件或者前端业务的开发,通常会配合后端自定义应用实现的服务来完成系统内数据的交互。当系统默认的界面不符合 UI/UE 设计需要、希望重新设计现有功能的前端展现时,我们也需要新增或者修改原有的组件源码。
为达成上述目标,除了使用 O2OA 平台的门户页面设计之外,针对复杂的前端交互设计,开发属于自己的 x_component 也是一种有效的方式。
本文主要介绍几种前端二次开发的方式,以及与流行前端框架(Vue、React)的集成方式。
用 VSCode 打开 O2OA 的源码目录,打开终端并输入以下命令:
npm install -g @o2oa/component-tools
![]()
该命令全局安装了@o2oa/component-tools,用于创建 O2OAcomponent。建议每次需要创建 component 时都运行此命令,以获取最新的更新。
然后进入 o2web/source 目录,运行 npm install。
cd o2web/source
npm install
执行完成后,就可以创建 component 了。
创建 component 的命令格式为:o2-cmpt create name,其中“name”就是要创建的 component 名称。例如创建一个名为“custom.homepage”的 component。
o2-cmpt create custom.homepage
运行后需要选择使用什么框架模式来创建 component,目前支持两种方式:vue3、o2oa 原生方式。(对于其它框架如 react 或者 Angular 的集成可以查询官方文档,其中有比较详细的步骤和说明。)
现在先介绍 o2oa 原生方式。选择“o2_native”然后回车,看到以下界面,即说明创建成功。
此时就可以在目录列表中看到“x_component_custom_homepage”这个目录。
展开目录后,可以看到文件结构:
$Main/目录:存放静态资源文件,包括图标、css、html 模板文件等
lp/目录:存放国际化语言包文件,zh-cn.js、en.js。
Main.js:component 的入口 js 文件。
如果在运行命令时,使用的是 windowss 的 PowerShell,可能会报错“…… 因为在此系统上禁止运行脚本……”的错误,有两个办法解决:1、用管理员权限打开 Windows PowerShell,运行 set-executionpolicy remotesigned 命令。然后先择 Y,回车即可运行脚本;2、是切换到 Command,如下图:
前端的打包部署使用 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
如果不出意外,运行正确后,会出现下面的信息:
此时新建的 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,然后用管理员身份登录,打开主菜单-系统设置
进入应用后选择“系统部署”,再点击最后的“部署组件”:
然后填入合适的信息
组件名称:可任意填写,但不能与已有组件重名。
组件标题:可任意填写,此信息实际上已经无效,组件的标题会自动获取 component 语言包中的 title 数据。
组件路径:这个必须与创建组件时的名称一致,这个例子中就是“custom.homepage”
组件图标:会自动获取 component 组件目录下的 appicon.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
运行完成后,重新刷新浏览器就可以看到修改后的效果了。
每次修改后运行部署命令,是令人不愉快的,所以我们可以运行以下命令,来监听文件变化并自动部署:
gulp watch --src x_component_custom_homepage --ev dev
之后每次修改组件的任何文件,都会自动部署到开发环境“dev”。
至此,native 类型的 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 创建完成。
然后选择“vue3”,会自动创建基于 vue3的 component。在安装完部分依赖之后,会询问几个问题:
1、需要输入开发服务器的 hosts
2、需要输入开发服务器的 center 服务端口,默认是80
3、需要输入开发服务器的 web 服务端口,默认是80
4、确认开发服务器是否使用 https,默认为 否(N)
其中开发服务器我们使用 px.o2oa.net, 其他选项都保持默认即可。
看到以下界面,说明 component 创建完成。
此时就可以在目录列表中看到“x_component_custom_workplace”这个目录。
展开目录后,就可以看到一个标准的 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
运行后,会启动本地开发服务器,并自动打开浏览器,访问。
添加路由插件:我们可以为 vue component 添加 vue router 插件,这和所有 vue 应用一样,可以通过 vue ui 添加,也可以使用命令:vue add router.
如果有源码存在未提交的 commit,会提示建议先提交后再安装插件。这里我们选择 y,继续安装。
安装一些依赖包后,会询问是否使用 histroy 模式,此处我们选择 n,即使用 hash 模式。
接着安装完成,可以看到 src 目录下增加了 router/index.js 和 view/目录下的两个视图。
重新启动本地开发服务器:npm run serve,即可在浏览器中看到效果:
此时再修改组件内容,如修改 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>
...
保存文件后,本地服务器会自动编译,浏览器会自动体现修改后的内容。
![]()
这样就可以方便地开发 component 组件了。
集成自定义应用
此时组件都是在本地服务器运行,部署到服务器的方法和 native 类型的组件是一样的。确保已存在 gulpconfig.js 文件并正确配置后,在 o2web/目录下运行 gulp 命令:
gulp x_component_custom_workplace --ev dev
就可以将组件部署到服务器了。
可以和 native 组件一样的方式,访问 custom.workplace 组件。
O2OA 支持使用 React 创建 component 组件,其方法与 Vue3 的组件非常类似。
我们再次打开终端,进入 o2web/source 目录,运行创建 component 命令,创建一个名为“custom.liveplace”的 component。
o2-cmpt create custom.liveplace
选择“react”后,会自动创建基于 React 的 component。安装完部分依赖后,同样会询问以下几个问题:
1、需要输入开发服务器的 hosts
2、需要输入开发服务器的 center 服务端口,默认是80
3、需要输入开发服务器的 web 服务端口,默认是80
4、确认开发服务器是否使用 https,默认为 否(N)
其中开发服务器我们使用 px.o2oa.net, 其他选项都保持默认即可。
看到以下界面,说明 component 创建完成。(React 应用创建过程较长,需要耐心等待一下)
此时就可以在目录列表中看到“x_component_custom_liveplace”这个目录。
展开目录后,就可以看到一个标准的 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
运行后,会启动本地开发服务器,并自动打开浏览器,访问。
此时可以修改组件源码,这里我们先修改一下欢迎信息。
修改中文语言信息:打开组件源码目录的 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": "在新浏览器窗口中打开"
}
刷新浏览器窗口后,就可以看到:
我们可以切换语言信息来看一下:点击右上角的个人头像,点击“个人设置”,将“语言设置”改为“English”,“保存个人信息”后,刷新页面。
就可以看到组件的语言信息已经切换过来了:
接下来就需要根据需求内容,进行组件开发了。
部署 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、认证体系、多语言特性、后端服务方法转换等特性,使开发者可以更好地专注于需要实现的业务。
相关问题讨论
在 Vue 应用中集成 O2OA 照着文档配置完之后报错
运行后需要选择使用什么框架模式来创建 component,目前支持两种方式:vue3、o2oa 原生方式。
查看原帖讨论 · 20,943 次浏览
Java 开源办公开发平台 O2OA V5.1.1 发布
上述要求我们除了使用 O2OA 平台的门户页面设计达到目标,针对于复杂的前端交互设计,开发属于自己的 x_component 也是一个有效的方式。
查看原帖讨论 · 12,389 次浏览
相关内容
上一篇:Custom应用前端代码编译
下一篇:没有了!