登录
文档目录
图片名称

  1. 为了降低属性输入组件的实现难度,使用混入类对组件中通用的属性,事件等进行了统一封装。

  2. 在实现一个新的值类型输入组件时,需要引入混入类,混入类中定义过的属性事件不需要重新定义,可直接使用。

  3. 混入类中明确定义了值输入组件与外部框架进行值传递的规范,实现时请严格按照规范执行,不按规范进行值传递可能造成不可预知缺陷。

  4. 属性值输入组件大致可以分为两类,一类是平铺型组件,一类为弹窗组件(modal, drawer)。相应的,混入也分为两类,需要引入对应的混入才能有相应的效果。


何时使用

  1. 弹窗型组件指的是有容器(如modal,drawer)包裹的,由属性栏上渲染的弹窗触发器触发的组件。

  2. 弹窗触发器为平铺组件,框架内置了默认的弹窗触发器,用户可参考默认触发器开发新的弹窗触发器

弹窗组件示例

源码展示

import { Component, Vue, Prop } from 'vue-property-decorator';
import { cloneDeep } from 'lodash';
import { ComponentNeedShow } from 'cloudpivot/common';
import { mixins } from 'vue-class-component';
@Component
export class PropertyModalBase extends mixins(ComponentNeedShow) {
  modalData: any = null;

  afterSHow(initData) {
    this.modalData = cloneDeep(initData);
  }

  backData(value: any) {
    this.$emit('backData', value);
  }

  otherValueChange(key, value) {
    this.$emit('otherValueChange', key, value);
  }
}
// 需要外部组件通过ref调用show方法才能显示的组件,需要混入此mixin
import { Component, Vue, Prop } from 'vue-property-decorator';
import { observeModal } from 'cloudpivot/common/src/utils/dom';
@Component
export class ComponentNeedShow extends Vue {
  //核心组件类型
  componentType: 'modal' | 'drawer' | 'popover' | 'big-dialog' = 'modal';

  componentVisible = false;

  //核心组件的包装class
  wrapClassName = '';

  noFooter = false;

  /**
   * 组件的显示只有一个入口,就是本方法
   * @param initData 初始化数据,某些数据需要在显示时传入
   */
  show(initData?: any) {
    let modalWrapClass = this.wrapClassName;
    if (this.wrapClassName.includes(' ')) {
      modalWrapClass = this.wrapClassName.split(' ')[0];
    }
    this.beforeShow(initData);
    this.componentVisible = true;
    this.afterShow(initData);
    if (this.componentType === 'modal' && modalWrapClass) {
      this.$nextTick(() => {
        observeModal(modalWrapClass, {
          noFooter: this.noFooter,
        });
      });
    }
  }

  /**
   * 组件的隐藏应该只有一个入口,就是本方法
   */
  hidden() {
    this.componentVisible = false;
    this.afterHidden();
  }

  beforeShow(initData?: any) {}

  afterShow(initData?: any) {}

  afterHidden() {}
}

属性说明

属性名
说明
类型
modalData
弹窗数据,在外部调用show方法时会当作参数传入
any
componentType
包装组件类型
'modal' | 'drawer' | 'popover' | 'big-dialog'
componentVisible
控制包装组件显隐
boolean
wrapClassName
包装组件类名
string
noFooter
modal类型下是否使用组件footer

函数说明
函数名
说明
参数
show
触发器点击时执行本方法可展示弹窗组件
弹窗数据
hidden
隐藏包装器,弹窗内部调用

beforeShow
展示前调用
弹窗数据
afterShow
展示后调用
弹窗数据
afterHidden
隐藏后调用

backData
属性值回传
新的属性值
otherValueChange
非controller直接绑定的属性值改变,不会触发subscribtion
属性key,属性value


何时使用

平铺型输入组件指的是组件直接渲染在属性名周围,不会有容器包裹。

源码展示

import { Component, Vue, Prop } from 'vue-property-decorator';
import { defaultNotEmpty } from '.';
import { isEqual } from 'lodash';
@Component
export class PropertyComponentBase extends Vue {
  @Prop({ default: false })
  disabled!: boolean;

  @Prop()
  defaultValue!: any;

  @Prop()
  value!: any;

  @Prop()
  maxLength!: number;

  @Prop()
  validError!: boolean;

  @Prop()
  title!: boolean;

  @Prop()
  getValueValidateErrorMessage!: Function;

  @Prop()
  isNotEmpty!: any;

  //是否展示错误文案
  @Prop()
  showErrorText!: boolean;

  @Prop()
  emptyErrorText!: string;

  //当前处于批量设计模式,批量设计下某些组件要更换渲染逻辑
  @Prop()
  batchMode!: boolean;

  get errorText() {
    if (!this.showErrorText) {
      return '';
    }

    if (this.validError) {
      return this.requiredErrorText || this.valuePatternErrorText;
    } else {
      return this.valuePatternErrorText;
    }
  }

  get requiredErrorText() {
    const emptyErrorText = this.emptyErrorText || `${this.title}不能为空`;
    if (typeof this.isNotEmpty === 'function' && !this.isNotEmpty(this.value)) {
      return emptyErrorText;
    } else if (!this.isNotEmpty && !defaultNotEmpty(this.value)) {
      return emptyErrorText;
    }
    return '';
  }

  get valuePatternErrorText() {
    if (
      typeof this.getValueValidateErrorMessage === 'function' &&
      this.getValueValidateErrorMessage({ value: this.value })
    ) {
      return this.getValueValidateErrorMessage({ value: this.value });
    } else {
      return '';
    }
  }

  mounted() {
    if (
      this.defaultValue !== undefined &&
      !isEqual(this.value, this.defaultValue)
    ) {
      //初始值的赋值只有在默认值与当前值不相等时才能进行,不然可能引发一些无用的监听逻辑
      if (this.isNotEmpty && typeof this.isNotEmpty === 'function') {
        if (!this.isNotEmpty(this.value)) {
          this.onValueChange(this.defaultValue);
        }
      } else if (!defaultNotEmpty(this.value)) {
        this.onValueChange(this.defaultValue);
      }
    }
  }

  onValueChange(newVal) {
    this.$emit('change', newVal);
  }

  //将数据保存在controller上,做缓存
  saveCacheData(key, value) {
    this.$emit('save', key, value);
  }

  otherValueChange(key, value) {
    this.$emit('otherValueChange', key, value);
  }

  //触发一次初始化的propertyChange事件
  initPropertyChange() {
    this.$emit('initPropertyChange');
  }
}

属性说明

属性名

说明

属性值类型

disabled

是否禁用,某些组件禁用态有不同的展示形式

boolean

defaultValue

值为空时使用到的默认值

any

value

any

maxLength

最大长度

number

validError

属性值校验状态

boolean

title

属性标题

string

getValueValidateErrorMessage

获取校验失败状态下的失败文案的函数

function

isNotEmpty

判断值不为空的函数

function

showErrorText

是否显示错误文案

boolean

emptyErrorText

错误显示文案

string

batchMode

是否开启批量模式,批量模式下组件展示可能发生变化

boolean

errorText

属性校验错误文案

string

函数说明

函数名

说明

参数

onValueChange

属性值改变,向外界传值函数

新的属性值

saveCacheValue

将中间值保留在controller上,刷新会被清空

保存的key,保存的value

otherValueChange

非controller直接绑定的属性值改变,不会触发subscribtion

目标属性key,新的目标属性值

initPropertyChange

触发一次初始化的propertyChange事件


河图属性设计器中内置了常用的属性输入组件

import { propertyRegister } from '../scripts';

import PropertyTextInput from './property-text-input.vue';
import PropertyTextArea from './property-text-area.vue';
import PropertyCheckbox from './property-checkbox.vue';
import PropertyDateSelect from './property-date-select.vue';
import PropertyModal from './property-modal.vue';
import PropertyRadio from './property-radio.vue';
import PropertySelect from './property-select.vue';
import PropertyStaffSelector from './property-staff-selector.vue';
import PropertySelectDataitem from './property-select-dataitem.vue';
import PropertySwitch from './proprety-switch.vue';
import PropertyIconSelect from './property-icon-select.vue';

propertyRegister
  .append('property-text-input', PropertyTextInput)
  .append('property-text-area', PropertyTextArea)
  .append('property-checkbox', PropertyCheckbox)
  .append('property-date-select', PropertyDateSelect)
  .append('property-modal', PropertyModal)
  .append('property-radio', PropertyRadio)
  .append('property-select', PropertySelect)
  .append('property-staff-selector', PropertyStaffSelector)
  .append('property-select-dataitem', PropertySelectDataitem)
  .append('property-switch', PropertySwitch)
  .append('property-icon-select', PropertyIconSelect);


开关选择器

何时使用

  • 需要表示开关状态/两种状态之间的切换时;

  • checkbox 的区别是,切换 switch 会直接触发状态改变,而 checkbox 一般用于状态标记,需要和提交操作配合。

代码演示

API

属性如下

属性

说明

类型

默认值

trueValue

自定义true值

PanelConfig

-

falseValue

自定义false值

number

-

FAQ


选人控件
何时使用

选择人员API

属性如下
属性
说明
类型
默认值
placeholder
缺省显示文案
placeholder
选择人员
multiple
是否允许多选
boolean
false
disabled
是否禁用
boolean
false
FAQ


下拉选择器。

何时使用

  • 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。

  • 当选项少时(少于 5 项),建议直接将选项平铺,使用 Radio 是更好的选择。

代码演示

API

属性如下

属性

说明

类型

默认值

placeholder

缺省显示文案

string

-

selectOptions

选项数据

OptionData[]

-

menuNoScroll

下拉菜单不支持滚动

boolean

false

multiple

支持多选

boolean

false

disabled

禁用

boolean

false

FAQ


选择数据项

何时使用

需要选中一个数据项时

代码演示

API

属性如下

属性

说明

类型

默认值

placeholder

缺省显示文案

string

请输入

dropdownPlaceRight

悬浮框显示在右侧

boolean

false

dataItems

数据项列表

DataItem[]

[]

filterFunc

数据项列表的筛选函数

function

-

modelName

数据项来源模型名称

string

-

menuNoScroll

下拉菜单不支持滚动

boolean

false

FAQ


单选框。

何时使用

  • 用于在多个备选项中选中单个状态。

  • 和 Select 的区别是,Radio 所有选项默认可见,方便用户在比较中选择,因此选项不宜过多。

代码演示

API

属性如下

属性

说明

类型

默认值

selectOptions

选项数据

OptionData

-

batchMode

批量模式

boolean

-

FAQ


弹窗组件触发器,是弹窗组件的外层包裹组件,负责显示弹窗已经清空数据相关逻辑

何时使用

  1. 属性输入需要使用到弹窗,并且弹窗外部触发组件符合一定规范

  2. 本组件只负责调用弹窗组件的show方法,请确保弹窗组件内拥有show方法

  3. 参数中的modalName是后续寻找关联弹窗组件的标识,查找范围还是在注册器注册的组件内

代码演示

API

属性如下

属性

说明

类型

默认值

modalName

弹窗组件定位名称

string

-

showSwitch

是否展示开关

boolean

false

disabled

是否禁用

boolean

false

showDeleteConfirm

删除数据时,是否显示确认弹窗

boolean | Function

false

confirmText

确认弹窗的文案

string

-

FAQ


图标选择控件

代码演示

FAQ


日期选择

代码演示

API

属性如下

属性

说明

类型

默认值

placeholder

属性栏配置对象

PanelConfig

-

disabled

是否禁用

boolean

false

FAQ


单行文本输入组件

何时使用

常规的文本输入

代码演示

API

属性如下

属性

说明

类型

默认值

placeholder

属性栏配置对象

PanelConfig

-

maxLength

最大长度

number

-

disabled

是否禁用

boolean

false

FAQ


多行文本输入组件

何时使用

多行文本输入

组件演示

API

属性如下

属性

说明

类型

默认值

placeholder

属性栏配置对象

PanelConfig

-

maxLength

最大长度

number

-

disabled

是否禁用

boolean

false

autoSize

行数限制

{minRows: number, maxRows: number}

{minRows: 6, maxRows: 6}

divideByTwo

计算长度时,中文算两个,英文算一个

boolean

false

showCount

在末尾处展示长度信息

boolean

false

FAQ


多选框组件

何时使用

  • 在一组可选项中进行多项选择时;

  • 单独使用可以表示两种状态之间的切换,和 switch 类似。区别在于切换 switch 会直接触发状态改变,而 checkbox 一般用于状态标记,需要和提交操作配合。

代码演示

API

属性如下

属性

说明

类型

默认值

selectOptions

选项数据

OptionData

-

disabled

是否禁用

boolean

false

FAQ


为了快速地添加输入组件以及使用已存在的组件,引入属性输入组件注册器

何时使用

需要使用河图属性设计器,并且仅靠内置的属性输入组件无法实现具体的值输入场景,需要引入新的值输入组件。

class PropertyRegister {
  assets: any = {};

  /**
   * 组件注册
   * @param viewType
   * @returns
   */
  append(componentName, componentAsset) {
    if (this.assets[componentName]) {
      //重复注册提示
      console.error(`The component ${componentName} has been registered!`);
      return;
    }
    this.assets[componentName] = componentAsset;
    return this;
  }

  //获取所有注册的组件
  getAssets(componentName?: string) {
    return componentName ? this.assets[componentName] : this.assets;
  }
}
export const propertyRegister = new PropertyRegister();
import { propertyRegister } from 'cloudpivot-designer/designer-core/property-panel';

import ReceiverSelectModal from './receiver-select-modal.vue';
import BindBizMethodModal from './bind-biz-method-modal.vue';
import SingleConditionGroup from './single-condition-group.vue';
import TwoConditionGroup from './two-condition-group.vue';
import RuleVariableModal from './rule-variable-modal.vue';

propertyRegister
  .append('receiver-select-modal', ReceiverSelectModal)
  .append('bind-biz-method-modal', BindBizMethodModal)
  .append('single-condition-group', SingleConditionGroup)
  .append('two-condition-group', TwoConditionGroup)
  .append('rule-variable-modal', RuleVariableModal);

注意事项

属性注册器添加组件,为了避免影响其他模块的正常使用,只允许添加组件,不允许覆盖组件


属性栏配置的价值在于简化属性的外在表现,隐藏输入组件的实现逻辑。

类型定义

/**
 * 属性面板的配置,包含多个属性的配置以及
 * 一些整体的配置
 */
export interface PanelConfig {
  //分组信息
  groups?: GroupInfo[];

  //必填属性code列表
  required: string[];

  //隐藏标题的属性code列表。注意:不设置属性title也可以达到此效果
  hiddenTitle?: string[];

  //属性信息
  properties: PropertySchema[];

  //事件订阅,各种回调函数
  subscriptions: PropertySubscription;
}

代码演示

import { PanelConfig } from 'cloudpivot-designer/property-panel';
import { DataItemType } from 'cloudpivot-form/form/schema';
import { verifyVariableInRule } from '../property-component-modal/scripts/verify-variable-in-rule';

const panelRuleProperty: PanelConfig = {
  groups: [
    {
      value: 'base',
      label: '基础属性',
      keys: ['modelName', 'code', 'name', 'remarks', 'ruleVariable'],
    },
  ],

  required: ['code', 'name'],

  properties: [
    {
      title: '触发模型',
      code: 'modelName',
      inputComponentName: 'property-text-input',
      options: {
        disabled: true,
      },
    },
    {
      title: '规则编码',
      code: 'code',
      inputComponentName: 'property-text-input',
      getRequiredErrorMessage: () => {
        return '业务规则编码不能为空!';
      },
      options: {
        disabled: (businessContext: any, propertiesData: any) => {
          //节点使用edit辨别是否保存过,规则使用id
          return !!propertiesData.id;
        },
      },
    },
    {
      title: '规则名称',
      code: 'name',
      inputComponentName: 'property-text-input',
      getRequiredErrorMessage: () => {
        return '业务规则名称不能为空!';
      },
      options: {
        maxLength: 50,
      },
    },
    {
      title: '规则描述',
      code: 'remarks',
      inputComponentName: 'property-text-area',
      options: {
        maxLength: 100,
      },
    },
    {
      title: '规则变量',
      code: 'ruleVariable',
      inputComponentName: 'property-modal',
      showDeleteConfirm: (variableList) => {
        return verifyVariableInRule([], false).then((verifyResult) => {
          return !verifyResult;
        });
      },
      confirmText: '规则变量已在规则中使用,请谨慎删除',
      options: {
        modalName: 'rule-variable-modal',
        tips: '如同表单字段,可以存放某个动作节点运行结果,可用于后续的判断、赋值。业务规则运行结束后,变量值会被清空重置',
        defaultValue: [],
      },
    },
  ],

  subscriptions: {
    onPropertyChange(
      code,
      value,
      oldValue,
      propertiesData,
      propertyControllerMap,
      businessContext,
    ) {
      if (code === 'ruleVariable') {
        verifyVariableInRule(value);
      }
    },
  },
};

export default panelRuleProperty;


属性的自定义渲染依赖于属性的自定义配置。属性的配置中需要指定属性的编码,标题,输入组件参数等重要信息。

类型定义

interface PropertySchema {
  //属性标题,如果不设置则表示不需要显示标题
  title?: string;
  //属性编码
  code: string;
  /**
   * 输入组件值的映射,如果只是简单通过code取可以不设置,如果是多个属性合并的场景,需要配置
   * 例如:code为a,b,c,valueMap为['a','b','c'],则输入组件的值为{a:1,b:2,c:3}
   **/
  valueMap?: string[] | any;
  //属性提示
  tips?: string;
  //输入组件名称
  inputComponentName: string;
  // 自定义的判空逻辑,如果不设置则默认为!!value
  isNotEmpty?: (value: any) => boolean;
  // 自定义的必填提示文案,如果不设置走默认文案逻辑
  getRequiredErrorMessage?: (controller, propertiesData) => string;
  // 必填以外的校验逻辑,校验后的提示文案
  getValueValidateErrorMessage?: (controller, propertiesData) => string;
  //默认值函数
  defaultValue?: (businessContext, propertiesData: any) => any;
  //弹窗组件是否需要显示删除确认弹窗
  showDeleteConfirm?: boolean | ((value: any) => boolean | Promise<boolean>);
  //弹窗组件删除确认弹窗文案
  confirmText?: string;
  //隐藏整个组件的判断函数,只支持简单场景,如果需要用到的数据在controller中,需要在subscription中处理
  hiddenFunc?: (propertiesData: any) => boolean;
  //属性值传递给组件时进行的映射
  inputValueTransform?: (value: any) => any;
  //组件值传递给属性时进行的映射
  outputValueTransform?: (value: any) => any;
  //组件的参数props
  options?: any;
}


对各个属性进行分组的分组信息,可设置分组的标题、问号提示、展示收起效果等

何时使用

需要对所有属性进行分组展示时,如果不需要分组展示,可不设置本属性。


类型定义

interface GroupInfo {
  label?: string;
  value: string;
  keys: string[];
  expend?: boolean;
  // 分组提示
  groupTips?: string;
  canExpand?: boolean;
  defaultExpand?: boolean;
}

代码示例

const panelWorkflowProperty: PanelConfig = {
  groups: [
    {
      value: 'baseConfig',
      label: '基础属性',
      keys: [
        'workflowCode',
        'workflowName',
        'icon',
        'document',
        'externalLinkEnable',
        'shortCode',
        'urgencyConfig',
      ],
      canExpand: true,
    },
    {
      value: 'workflowTimeoutConfig',
      label: '流程超时配置',
      keys: ['timeoutConfig'],
    },
    {
      value: 'workflowExceptionNotice',
      label: '流程异常通知',
      keys: ['exceptionNotifyConfig'],
      groupTips: '当流程发生异常时,通知配置好的人员',
      canExpand: true,
    },
    {
      value: 'workflowEvent',
      label: '流程事件',
      keys: [
        'startEventHandler',
        'endEventHandler',
        'cancelEventHandler',
        'activateEventHandler',
      ],
      canExpand: true,
    },
    {
      value: 'workflowMessage',
      label: '流程消息通知',
      keys: ['messageManage', 'todoDataItems'],
      groupTips: '可定义流程流转到各节点时,审批人接收到的信息',
      canExpand: true,
    },
    {
      value: 'workflowStartConfig',
      label: '流程发起配置',
      keys: ['workflowStartConfig'],
      canExpand: true,
    },
    {
      value: 'workflowPrivilege',
      label: '流程运维特权人',
      keys: ['workflowPrivilegeSetting'],
      groupTips: '配置对该流程拥有运维操作权限的人',
      canExpand: true,
    },
  ],
};


图片名称
  • 组件混入
  • 弹窗型组件混入
  • 平铺型输入组件混入
  • 属性设计器内置输入组件
  • property-switch 开关选择器
  • property-staff-selector
  • property-select
  • property-select-dataitem
  • property-radio
  • property-modal
  • property-icon-select
  • property-date-select
  • property-text-input
  • property-text-area
  • property-checkbox
  • 属性输入组件注册器
  • 属性栏配置
  • 属性配置properties
  • 分组配置groups