技术文章

在上一个章节中,我们介绍了在O2OA中使用Angular开发应用,编译后在O2服务器的webServer中运行。如果您考虑完全脱离O2的web服务器,自己搭建web服务器,那就请阅读本章。
我们还是使用Angular CLI来搭建我们的应用,实现一个简单门户,显示当前用户的最新待办、通过O2视图展现信息类文档,以及启动指定流程和发布文档功能。效果如下:

本文适用于如下版本:
O2OA版本要求:5.1及以上版本;
Angular版本:本文撰写时,Angular版本是9.1.11。
Angular CLI版本:本文撰写时,Angular CLI版本是9.1.9。
通过ng version命令查看版本如下:

我们使用 Angular CLI 工具搭建 Angular 开发环境,首先我们需要安装Node.js和npm包管理器,然后我们通过以下命令安装 Angular CLI :
npm install -g @angular/cli
此方法全局安装了Angular CLI,然后通过以下命令查看相关版本信息:
ng version
可以通过以下命令,查看Angular CLI 的更多命令:
ng help
要创建一个新的工作空间和初始入门应用:
运行 CLI 命令 ng new 并提供 my-app 名称作为参数,如下所示:
ng new angular-app
ng new 命令会提示你提供要把哪些特性包含在初始应用中。按 Enter 或 Return 键可以接受默认值。
Angular CLI 会安装必要的 Angular npm 包和其它依赖包。这可能要花几分钟的时间。
此时创建了一个名为angular-app的应用。

创建完成后生成目录如下:

这步中,我们需要在src目录下创建一个o2目录(目录名称可随意修改,后续的相关引用和配置也随之修改即可),将O2服务器的webServer下的所有文件夹拷贝到src/o2目录下:

在src/index.html的head中添加O2脚本引入:

修改public/x_desktop/res/config/config.json文件:
{
"center": [
{
"port": "20030", //O2服务器中心服务器端口
"host": "develop.o2oa.net" //O2服务器中心服务器Host
}
],
"applicationServer": {
"host": "develop.o2oa.net" //O2应用服务器Host
},
"sessionStorageEnable": true,
"initManagerChanged": true,
"initManagerName": "",
...
}此文件主要修改两部分内容:
1、center部分,修改为要访问的O2中心服务器地址和端口;
2、applicationServer部分,修改为要访问的O2应用服务器地址,如果没有applicationServer,就添加一个。集群环境下,可配置应用服务器负载地址;
3、sessionStorageEnable设置为true,启用通过sessionStorage传递登陆后的token,解决跨域cookies传递问题。(生产环境出于安全性考虑,一般情况下不要设置此项)
为了方便后续引入,我们在src下创建一个o2.js,添加以下代码:
let o2 = window.o2;
let layout = window.layout;
export {o2, layout};修改src/main.ts文件如下:
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
//引入o2的layout对象
import { layout } from './o2';
if (environment.production) {
enableProdMode();
}
//当o2载入完成后启动Angular Module
layout.addReady(() => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
}
);之后就是修改和创建组件了,直到编译运行之前,和上一章完全一样。
我们要实现展现待办和展现信息两部分内容,所以我们需要添加两个组件。通过以下CLI命令,我们可以让Angular-CLI自动帮我们创建好组件。
ng generate component o2-task
ng generate component o2-info
以上两条命令创建了两个组件:
o2-task:用于展现待办,并通过一个按钮启动指定流程;
o2-info:用于通过O2视图展现信息,并通过一个按钮创建新文档。
创建完组件,我们可以看到在app目录下,新建了两个目录:o2-task和o2-info。每个目录下分别有以下文件:
*.component.css | 组件样式文件 |
*.component.html | 组件模板文件 |
*.component.spec.ts | 组件的单元测试文件 |
*.component.ts | 组件脚本文件 |

我们再打开src/app.module.ts文件,发现Angular已经为我们添加了新建组件的引用:

现在我们需要修改app.component组件来使用我们新创建的组件,修改src/app/app.component.ts为如下内容:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
//仅修改了此处的title
title = 'Angular With O2OA';
}修改src/app/app.component.html为如下内容:
<div class="toolbar">{{title}}</div>
<div class="content">
<app-o2-task></app-o2-task>
<app-o2-info></app-o2-info>
</div>此处我们删除了原来的所有内容,并增加了<app-o2-task></app-o2-task>和<app-o2-info></app-o2-info>用来渲染o2-task和o2-info组件。
修改src/app/app.component.css为如下内容:
.toolbar {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60px;
line-height: 60px;
align-items: center;
text-align: center;
background-color: #1976d2;
color: white;
font-weight: 600;
font-size: 32px;
}
.content {
margin: 80px auto 0 auto;
width: 90%;
overflow: hidden;
}接着我们修改o2-task组件,修改src/app/o2-task/o2-task.component.css文件如下:
.taskContent{
height: 500px;
width: 48%;
float: left;
padding: 10px;
border: 1px solid #eeeeee;
}
.taskItem {
height: 40px;
line-height: 40px;
color: #666666;
cursor: pointer;
border-bottom: 1px solid #eeeeee;
}
.taskTitle {
height: 50px;
line-height: 50px;
font-weight: bold;
font-size: 18px;
color: #333333;
padding: 0 10px;
background-color: #eeeeee;
margin-bottom: 5px;
}
button {
padding: 3px 20px;
text-align: center;
background: #0f81cc;
border: 1px solid #ffffff;
margin-top: 8px;
color: #ffffff;
font-size: 18px;
float: right;
cursor: pointer;
}修改src/app/o2-task/o2-task.component.html文件如下:
<div class="taskContent">
<div class="taskTitle">
<span>{{title}}</span>
<!--发起流程按钮,绑定click事件到组件的startProcess方法-->
<button (click)="startProcess()">发起流程</button>
</div>
<!--通过ngfor循环tasks,展现每一条待办-->
<div *ngFor="let task of tasks">
<div class="taskItem" (click)="openTask(task.work)">
<a [title]="task.title">
{{ task.title || "无标题" }}
</a>
</div>
</div>
</div>修改src/app/o2-task/o2-task.component.ts文件如下:
import { Component, OnInit } from '@angular/core';
//引入o2对象
import {o2} from "../../o2";
@Component({
//组件的选择器,对应我们在app.component.html模板中的<app-o2-task>
selector: 'app-o2-task',
templateUrl: './o2-task.component.html',
styleUrls: ['./o2-task.component.css']
})
export class O2TaskComponent implements OnInit {
tasks = [];
title = "我的待办";
constructor() {}
ngOnInit(): void {
//通过调用O2平台的服务,获取当前用户的前20条待办
o2.Actions.load("x_processplatform_assemble_surface").TaskAction.V2ListPaging(1,20, {}, (json)=>{
this.tasks = json.data;
});
}
startProcess() {
//通过o2.env对象启动流程
//o2.env对象即是在O2门户页面的脚本中的this指向,可以使用其方法。
//请将“application-name”和“process-name”修改为您的流程应用名称和流程名
o2.env.page.startProcess("application-name", "process-name");
}
openTask(id) {
//通过o2.env对象打开待办
o2.env.page.openWork(id);
}
}以上代码中,有关Angular的内容,请参考Angular的官方文档。
接着我们修改o2-task组件,修改src/app/o2-task/o2-info.component.css文件如下:
.viewContent{
height: 500px;
width: 48%;
float: right;
padding: 10px;
border: 1px solid #eeeeee;
}
.view {
height: 460px;
}
.viewTitle {
height: 50px;
line-height: 50px;
font-weight: bold;
font-size: 18px;
color: #333333;
padding: 0 10px;
background-color: #eeeeee;
margin-bottom: 5px;
}
button {
padding: 3px 20px;
text-align: center;
background: #0f81cc;
border: 1px solid #ffffff;
margin-top: 8px;
color: #ffffff;
font-size: 18px;
float: right;
cursor: pointer;
}修改src/app/o2-task/o2-task.component.html文件如下:
<div class="viewContent">
<div class="viewTitle">
<span>{{title}}</span>
<button (click)="createDocument()">新建信息</button>
</div>
<!--用于视图展现的dom对象-->
<div #viewContent class="view"></div>
</div>修改src/app/o2-task/o2-task.component.ts文件如下:
import {Component, ElementRef, OnInit,ViewChild} from '@angular/core';
//引入o2对象
import {o2} from "../../o2";
@Component({
//组件的选择器,对应我们在app.component.html模板中的<app-o2-info>
selector: 'app-o2-info',
templateUrl: './o2-info.component.html',
styleUrls: ['./o2-info.component.css']
})
export class O2InfoComponent implements OnInit {
//要展现的视图信息,我们必须在O2平台创建好名为“内容管理数据”的数据应用和“所有信息”视图
//修改此值,可显示不同的视图
viewApp="内容管理数据";
viewName="所有信息";
//获取展现视图的原生Dom对象
@ViewChild("viewContent") content: ElementRef;
title = "最新信息";
constructor() {
//新建一个Viewer对象,用于展现指定的视图
//将Viewer展现挂载到viewContentst的原生DOM对象上,就是模板中的<div #viewContent class="view"></div>
o2.xDesktop.requireApp("query.Query", "Viewer", function(){
new o2.xApplication.query.Query.Viewer(this.content.nativeElement, {
"application": this.viewApp,
"viewName": this.viewName,
});
}.bind(this));
}
ngOnInit(): void {
}
createDocument(){
//通过o2.env对象新建内容管理文档
//o2.env对象即是在O2门户页面的脚本中的this指向,可以使用其方法。
//createDocument方法创建内容管理文档,可传入栏目和分类参数,请参考API文档
o2.env.page.createDocument();
}
}以上代码中,有关Angular的内容,请参考Angular的官方文档。
我们完成了上述开发工作,还需要几项配置,就可以编译并运行我们的应用了。
修改angular.json文件,找到对应应用下的architect.build.options,assets,增加一个元素:
{"glob": "**/*", "input": "src/o2/", "output": "/"}
这行代码表示:将o2目录下的所有文件,在编译时输出到编译目录的根目录下。(我们建议将o2的所有文件编译到根目录下,否则将要修改一些静态文件的引用,这个我们在后面介绍)。
接着,我们可以运行开发服务器了,使用以下任一命令来运行开发服务器:
ng serve --open
Angular会为我们编译代码,并启动一个web服务器,默认端口4200,并自动打开默认浏览器,运行我们的应用,就可以看到和上一章相同的效果了。(Angular默认不支持IE浏览器,可以通过配置src/polyfills.ts、browserslist、tsconfig.json等文件来生成兼容的版本,但从V10开始Angular已经放弃了对IE9、10和IE Mobile的支持。详见Angular官方文档。)
如果您未登录到服务器,会出现登录页面,登录后就可以看到实现的效果了。
登陆后:

您可以接着修改代码,每次修改保存后,Angular会自动编译,并刷新浏览器,及时看到修改效果。
开发完成后,可使用命令:
ng build
Angular会在将所有的代码编译到dist目录下,你就可以将dist中的内容部署到任意的web服务器了。
前面,我们在angular.json文件配置了输出路径到根目录,这是我们建议的方式,但如果您一定要将O2文件放置到其他目录,那么你需要做以下几件事:
1、在angular.json文件中更改刚刚的assets配置为:
//假设我们将O2文件全部放置到/o2目录下
{"glob": "**/*", "input": "src/o2/", "output": "/o2/"}2、修改src/o2.js文件
let o2 = window.o2;
let layout = window.layout;
//修改o2的base属性
o2.base = "/o2/";
export {o2, layout};然后可以正常编译和运行应用了。
至此,我们将三个目前最主流的前端框架于O2OA的集成开发都介绍完了,其实还是万变不离其宗,正确的应用到O2中的全局对象o2和layout,您就可以干任何事了。如果您使用其他的前端框架,也可以参考此系列文章中的方法。
希望这个系列能对您有所帮助,感谢您对O2OA的关注!