我们在业务开发中,经常会遇到自定义的视图或字段。有时候期望点击某一块区域的时候,打开一个弹窗或者是跳转新页面亦或者是执行服务端动作(调接口),但是希望这个动作是界面设计器拖拽进来的。
这篇文章详细的讲解了自定义的视图、字段怎么执行界面设计器拖出来的按钮。
自定义视图
1: 先设计一个页面,把对应的动作拖拽进来,可以不需要配置字段
2: 将该页面绑定菜单
3: 自定义对应的页面
当我们自定义视图的时候,首先会注册一个视图,下面是我自定义的一个表单视图
registerLayout(
  `<view type="FORM">
    <element widget="actionBar" slot="actionBar">
        <xslot name="actions" />
    </element>
    <element widget="MyWidget" slot="form">
        <xslot name="fields" />
    </element>
</view>`,
  {
    moduleName: 'ys0328',
    model: 'ys0328.k2.Model0000000453',
    actionName: 'MenuuiMenu78ec23b054314ff5a12b4fe95fe4d7b5',
    viewType: ViewType.Form
  }
);我自定义了一个叫做MyWidget的 element,下面是对应的ts代码
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'MyWidget' }))
export class MyWidgetManageWidget extends FormWidget {
  public initialize(props): this {
    super.initialize(props);
    this.setComponent(MyVue);
    return this;
  }
}这是对应的 vue 文件: MyVue.vue
<template>
  <div @click="onClick">点击执行动作</div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  export default defineComponent({
    props: ['onClick']
  });
</script>这个时候,我希望点击的时候,执行 onClick,会执行对应的动作,这时只需要在对应的 ts 文件中写对应的代码逻辑即可:
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'MyWidget' }))
export class MyWidgetManageWidget extends BaseElementWidget {
  // 获取当前页面所有的按钮
  @Widget.Reactive()
  public get modelActions() {
    return this.metadataRuntimeContext.model.modelActions || []
  }
  // 用来解析上下文表达式的,如果不需要,可以删除
  public executeCustomExpression<T>(
    parameters: Partial<ExpressionRunParam>,
    expression: string,
    errorValue?: T
  ): T | string | undefined {
    const scene = this.scene;
    return Expression.run(
      {
        activeRecords: parameters.activeRecords,
        rootRecord: parameters.rootRecord,
        openerRecord: parameters.openerRecord,
        scene: parameters.scene || scene,
        activeRecord: parameters.activeRecord
      } as ExpressionRunParam,
      expression,
      errorValue
    );
  }
  // 点击事件
  @Widget.Method()
  public onClick() {
    // 找到对应的按钮
    const action = this.modelActions.find((a) => a.label === '动作的显示名称');
     /**
    * 如果是服务端动作,就执行 executeServerAction
    */
    // executeServerAction(action, 参数对象) // 第二个参数是调用对应的接口传递的参数
 /**
    * 如果是跳转动作,就执行 executeViewAction
    */
    executeViewAction(action);
    /**
    * 如果跳转动作打开的视图需要通过id去查询数据,可以这样配置, 一般用于打开编辑、详情页
    */
    // executeViewAction(action, undefined, undefined, {id: 'xxxx'});
    /**
    * 如果跳转动作打开的视图需要需要额外的上下文参数,可以这样配置
    */
    // const _action = {
    //   ...action,
    //   context: {
    //     ...(action.context || {}),
    //     name: '123',
    //     code: '232'
    //   }
    // } as RuntimeViewAction
    // executeViewAction(_action, undefined, undefined, {id: 'xxxx'});
     /**
    * 如果跳转动作打开的视图需要上下文参数是在配置在对应动作上面,可以这样去解析上下文表达式
    */
    // const context = action.context || {}
    // const context = (action as RuntimeViewAction).context || {}
    // const parseContext = {}
    // const data = {} // 这是自己的数据源
    // Object.entries(context).forEach(([key, value]) => {
    //   if(typeof value === 'string') {
    //     parseContext[key] = this.executeCustomExpression({activeRecord: data, rootRecord: data,openerRecord: data}, value)
    //   }
    // })
    // executeViewAction({
    //   ...action,
    //   context:parseContext
    // } as RuntimeViewAction, undefined, undefined, {id: 'xxxx'});
  }
  public initialize(props: BaseElementWidgetProps): this {
    super.initialize(props);
    this.setComponent(MyVue);
    return this;
  }
}以上我们就完成的自定义的视图如何触发界面设计器拖拽出来的按钮。
这是页面运行时的效果图


自定义字段
先自定义对应的字段,下面是我自定义的字段
@SPI.ClassFactory(
  BaseFieldWidget.Token({
    viewType: ViewType.Form,
    ttype: ModelFieldType.String,
    widget: 'MyField'
  })
)
export class MyFieldWidget extends FormFieldWidget {
  // 获取当前页面所有的按钮
  @Widget.Reactive()
  public get modelActions() {
    return this.metadataRuntimeContext.model.modelActions || []
  }
  // 点击事件
  @Widget.Method()
  public onClick() {
    // 找到对应的按钮
    const action = this.modelActions.find((a) => a.label === '点击打开弹窗');
    // 执行按钮
    executeViewAction(action as any);
  }
  public initialize(props: BaseElementWidgetProps): this {
    super.initialize(props);
    this.setComponent(MyVue);
    return this;
  }
}
<template>
  <div @click="onClick">点击字段打开弹窗</div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  export default defineComponent({
    props: ['onClick']
  });
</script>其实不管是自定义的视图还是字段,里面执行动作的写法其实是一样的。
权限控制
如果当前系统用到了权限,那么我们在执行 action 时,需要判断当前 action 是否存在,因为当用户没有该 action 权限的时候,前端是获取不到对应的 action。
@Widget.Reactive()
public get hasMyAction() {
  return this.metadataRuntimeContext.model.modelActions.find(a => a.name === 'myAction')
}<template> <div @click="onClick" v-if="hasMyAction">点击打开弹窗</div> </template>template我们只需要定义一个计算属性,用来处理当前 action 是否存在,最后在 vue 模版里面使用 v-if 来控制是否显示。
Oinone社区 作者:汤乾华原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/4384.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验
 
                
