跳转到内容

视图 controller 语法

controller 可以让前端自定义写一些代码逻辑, 可使用 ts/es6 编写。

注意:在用 getContainerByKey 时确保数据容器上没有写 id 属性,id 会覆盖当前数据容器的 key

可依赖的方法

// nusi-sdk:
import {
state, // 对应mobx的observable
action, // 对应mobx的action
computed, // 对应mobx的computed
_, // 对应 lodash
Controller, // Controller 基类
utils, // 工具方法
showMessage, // 显示自定义消息
PubSub, // 订阅发布
} from "nusi-sdk";
属性说明
state、action、computedmobx 的状态管理,详情可看 mobx 文档和下方 demo
_lodash 对象,可以用 lodash 里面的任何方法: 比如 _.includes([1, 2, 3], 1);
Controller必须继承它
utilsutils
showMessagefunction showMessage(message: IMessage): Promise;
PubSub发布订阅实例

utils

方法类型说明
openUrl(url: string, isBlank: boolean = true) => void isBlank 默认值 为 true浏览器中打开连接,url 可以是外部链接,可以是应用内链接, isBlank 指定是不是另开 tab 打开
getModuleApiUrl(moduleKey: string) => string根据模块 key 获取后端服务对应请求服务链接
triggerServerAction(actionKey: string, data: IActionContext) => void, IActionContext调用 serverAction
confirm(context: string) => void打开确认框,确认框内容是 context

IActionContext

export interface IActionContext {
modelKey?: string;
record?: IDictionary | IDictionary[];
related?: IRelatedModel;
env?: IDictionary;
process?: string; // process action key
actionLabel?: string; // for friendly log
}
export interface IRelatedModel {
model: string;
id: string[] | string;
field: string;
autoGenerate?: boolean;
}

IMessage

| 属性名 | 类型 | 描述 | | ------- | ------------------ | ---------------------------------------------------------------------------------------- | --------- | -------- | ----------------------------------------------------------------------------------- | | level | “Weak” | “Strong” | 不必须,默认为 Weak, Weak 用 Toast 显示,会自动消失,Strong 用信息提示框显示,需要点确定 | | message | string | 信息提示内容 | | type | "Success" | "Info" | "Warning" | "Error" | 不必须,type 指定了 Strong level 时信息提示类型的。表现在信息提示内容前的图标不一样 |

PubSub

发布订阅实例

方法参数描述
subscribe(topic: string, listener: (data) => void, key?: string, followLast = false) => void订阅
publish(topic: string, data?: any, key?: string) => void发布

Controller 类实现了的方法和属性如下

controller 中的方法都注入到了 dsl 当做上下文,所以在 dsl 也可以直接使用

方法

方法参数返回值说明
getContainerByKeygetContainerByKey(containerKey), containerKey: dsl 中定义在数据容器上的 keygetContainerByKey 返回值获取数据容器上相关数据和方法
goBackgoBack()-回到上个页面
triggerViewActiontriggerViewAction(action: string, { context,openViewType, env, realtedModel, payloadCallBack, modelKey }: IParam)-跳转 viewAction

getContainerByKey 返回参数

{
data: IDictionary[] | IDictionary; // 数据容器对应的数据
clearData: () => void; // 清除数据容器数据
refresh: () => void; // 刷新数据容器
updateData?: Function; // 更新数据容器数据
validateData?: (fields: string[], index?: number) => void; // 校验数据容器中的指定字段,如果是是TableForm,需指定当前行的index
}

triggerViewAction param 参数

{
context?: IDictionary | IDictionary[] //传入到下个页面的 context,
openViewType: OpenViewType//页面打开类型,
env?: IDictionary//传到下个页面的 env,
relatedModel?: IRelatedModel,
modelKey: string,
afterClose: () => void, // 关闭页面后执行的回调
payloadCallBack: ({
modelKey?: string
record?: IDictionary | IDictionary[]
related?: IRelatedModel
env?: IDictionary
process?: string // process action key
actionLabel?: string // for friendly log
}) => void //payload 回调类型
}

属性

名称描述
pageContext初始值为页面 search 的 key-value,可能会被覆盖
i18ni18n 相关 i18n.get(‘警告’).d(‘警告’) 带参数 i18n.get(‘fn_编辑模型’, { model: modelInfo.name })

Controller 生命周期

名称说明
pageDidLoad页面挂载的方法,同 react componentDidMount
pageDidUpdate会在更新后会被立即调用。首次渲染不会执行此方法。同react componentDidUpdate
pageUnLoad会在页面卸载及销毁之前直接调用, 同react componentWillUnmount

示例

import { state, action, _, computed, Controller } from "nusi-sdk";
export default class extends Controller {
@state
data = [];
@computed get value() {
return _.filter(this.data, ({ show }) => show);
}
@action
onChange() {}
}

典型场景

获取其他数据容器数据

<View title="用户详情">
<Detail key="user" model="user2_User">
<Fields>
<Field name="name"/>
<Field name="locked" />
</Fields>
</Detail>
<Table model="user2_Address" related="owner:user">
<Fields>
<Field name="isHome" :show="getContainerByKey('user').data.locked" />
<Field name="city" />
</Fields>
</Table>
</View>

表单联动

<View title="用户地址编辑">
<Form key="user" model="user2_User" @onFieldValueChange="userFieldChange">
<Fields>
<Field name="sex" />
<Field name="name" />
<Field name="age" />
<Field name="username" />
</Fields>
<Actions>
<Action layout="Header" logicFlow="user2_User_update" label="更新" />
</Actions>
</Form>
</View>
import { Controller } from "nusi-sdk";
export default class extends Controller {
// 当字段值发生变化时触发以下方法
userFieldChange = (fieldName: string, value: string) => {
if (fieldName === "name") {
// 判断当前哪个字段的值发生变化
const user = this.getContainerByKey("user"); // 根据 key 获取数据容器
user.updateData({
// 更新数据容器数据
username: value,
});
}
};
}

触发 Action

<View title="用户地址编辑">
<Form key="user" model="user2_User">
<Fields>
<Field name="sex" />
<Field name="name" />
<Field name="age" />
<Field name="username" />
</Fields>
<Actions>
<Action layout="Header" @action="doAction" label="更新" />
</Actions>
</Form>
</View>
import { Controller, utils } from "nusi-sdk";
export default class extends Controller {
doAction = ({ context }) => {
// 触发 ViewAction
this.triggerViewAction("actionKey", {
context,
modelKey: "user2_User",
openViewType: "Dialog", // 默认为 Self
env: { a: 1 },
});
// 触发 ServerAction
utils.triggerServerAction("actionKey", {
record: context,
modelKey: "user2_User",
env: { a: 1 },
actionLabel: "提交", // 用于log记录的名称,在xml中则是按钮文字
});
};
}

TableForm 联动

<View title="用户详情编辑">
<Form model="user2_User" key="test">
<Fields>
<Field name="name"/>
<Field name="locked" />
<Field name="age" />
<Field name="code" />
<Field name="username" />
</Fields>
<Actions>
<Action type="Submit" label="新增" :show="!this.data.id" logicFlow="user2_User_create" after="GoBack" layout="Footer"/>
<Action type="Submit" label="修改" :show="!!this.data.id" logicFlow="user2_User_update" after="GoBack" layout="Footer"/>
</Actions>
</Form>
<TableForm key="transFee" model="custom_TransFee" @onFieldValueChange="tableFormFieldChange" lookupFrom="test.transFee">
<Fields>
<Field name="bus" :test="this.data" />
<Field name="airplain" />
<Field name="total" readonly />
</Fields>
</TableForm>
</View>
import { Controller } from "nusi-sdk";
export default class extends Controller {
// 当字段值发生变化时触发以下方法
calcTotalFee = (rowData: any = {}) => {
const { bus = 0, airplain = 0 } = rowData;
return bus + airplain;
};
tableFormFieldChange = (value: string, fieldName: string, index: number) => {
const user = this.getContainerByKey("transFee"); // 根据 key 获取数据容器
const data = [...user.data]; // 获取这个数据容器的data
const rowData = { ...data[index], total: this.calcTotalFee(data[index]) };
data.splice(index, 1, rowData);
user.updateData(data);
};
}

动态校验根据(不同情况执行不同的校验规则)

controller 里提供了 validateData(fields, index?)  函数用于校验指定字段,该函数接收 1-2 个参数: fields、index , fields  是个数组([‘field1’, ‘field2’, …])表示要去校验的相应字段,必填;只有在 tableForm  里 index  才是必须,指定当前行。

<TableForm key="qualificationLicense" @onFieldValueChange="tableFormFieldChange">
<Fields>
<Field label="到期日期" name="expirationTime">
<Validations>
<Validation :required="!this.record.alwaysValid || this.record.alwaysValid == 'false'" message="到期日期不能为空" />
</Validations>
</Field>
<Field name="alwaysValid" label="是否长期有效"/>
</Fields>
</TableForm>

expirationTime 的必填与否,取决于字段 alwaysValid 的值,所以当 alwaysValid 发生 change 的时候,要去重新校验 expirationTime

import { Controller } from "nusi-sdk";
export default class extends Controller {
tableFormFieldChange = (value: string, fieldName: string, index: number) => {
const license = this.getContainerByKey("qualificationLicense"); // 根据 key 获取数据容器
if (fieldName === "alwaysValid") {
setTimeout(() => {
license.validateData(["expirationTime"], index);
}, 0);
}
};
}

PubSub(页面通信)

如果遇到多个页面需要通信的场景可以通过 PubSub 来解决

import { Controller, PubSub } from "nusi-sdk";
// Page A
export default class extends Controller {
constructor() {
super();
this.listener = PubSub.subscribe("moduleKey/yourTopic", (data) => {
// do something
});
}
pageUnLoad = () => {
this.listener.remove();
};
}
// Page B
export default class extends Controller {
onSave = (data) => {
PubSub.publish("moduleKey/yourTopic", data);
};
}
// 自定义数据容器、控件
import { PubSub } from "@terminus/nusi-engine";