deploy.md 18 KB

工具库功能和使用手册   牧语  开发文档

mjs 配置型文档


宜搭公式

常用公式

  1. 日期格式为数值, 如 7 - 12 点不允许点餐:
   OR(GT(VALUE(TEXT(DATE(TIMESTAMP(SYSTIME())),"HHmm")),1600),GT(700,VALUE(TEXT(DATE(TIMESTAMP(SYSTIME())),"HHmm"))))
  1. 获取天数差值:DYAS(DATE(结束日期组件),DATE(开始日期组件))

  2. 由时间戳生成编号 CONCATENATE("PRO",LEFT(TIMESTAMP(SYSTIME()),10)), CONCATENATE("COC",TEXT(TODAY(),"yyyyMMddHHmmSS"))

  3. 日期组件默认值:TIMESTAMP(SYSTIME())

  4. 数据关联两个字段, 数据联动处理, 获取拼接字段的其中一个值:ARRAYGET(SPLIT(​ 合同编号 ​,"-"), 1)

  5. 明细数据某一列不能重复验证: 自定义验证函数 - 不能使用 scope, 移到 change 事件,通过 forceValid 实现

function validateRule(value, state, ctx) {
  if (value == "自定义回款") return true
  const details = ctx.store.getData("tableField_kexuivc3").fieldData.value
  const arr = details.filter(detail => detail["selectField_kexuivc5"].fieldData.value == value)
  return arr.length < 2
}
  1. 映射人员搜索框人员信息: USERFIELD(人员搜索框,"userId") -- name; 获取部门: DEPTNAME(人员搜索框)

高级公式

  • 使用高级公式,条件如涉及到当期表,则条件的首参必须是目标表字段:否则报:主条件参数错误
  • 高级公式 crud:可执行明细插入明细,在关联审批流时。不能同时操作多个明细,或明细和明细外组件

2.表间数据关联

从一个表单或者流程页面,自动加载其它表单或者流程的明细数据,自动填充到当前页面指定组件内

前言

两个准备工作,整个应用仅仅配置一次。上线前请切换生产地址,通过数据源配置方案仅修改一次即可

  • 提供应用的 code 和 secret:【应用设置】➜【应用数据】➜【应用编码】|【应用秘钥】
  • 在数据源添加库地址,mjs_LIB 公共库地址:https://aliwork.zitoo.com.cn/mjs/mjs.min.js

效果

demo 页面

  1. 场景:通过下拉条件关联目标单据值
  2. 方案:支持多条件查询,支持查询后数据过滤,支持查询和明细赋值默认值:将 src 设置为空
  3. 进阶:可实现一表查询更新多明细;多个明细来自多个数据源;主表更新主表:兼容一些当前页面需要公式或者数据联动情况【若需要作为联动条件,需要修复】;明细加载主表数据
  4. 备注:取消所有组件的数据联动,若无异常可不取消 【新的宜搭版本下拉修改优先级偶尔会高于 js 赋值,因此不取消可能会出现查询结果异常】

参数

  • 全局编码命名规则说明:

    • cur 即 current,通常指当前页面内组件 ID;
    • src 即 source,通常值源表页面内组件 ID;
    • def 即 default,通常指默认值,默认值优先级低于来源表数据
  • 一些必填字段情况说明:

    • formId:来源数据的表单 Id,格式为 FORM-xxxx,可在应用设置或者直接打开目标页面,在地址栏粘贴
    • conditions: 查询条件,格式为 [{ src: "", cur: "", def: "" }];,def 优于 src, src 和 cur 均需要传入组件 ID,支持多条件查询
    • funcFilter:明细集合数据过滤方法,若不需要过滤则置空。格式为 detail => detail["compId"] == ""
  • 一些非必填选配字段说明:

    • compId:报错的提示到输入框,若不传入则报错会以 toast 方式进行提示。报错提示在输入框,可阻断提交【建议配置】
    • isForm:数据查询是否来自表单,流程数据通过表单方式亦能查询【通常不需要配置】
    • errMsg:查询失败报错提示优先使用接口报错,若查询为空,默认提示为 未查询到匹配数据【通常不需要配置】

案例

打开页面的 js 功能,复制如下代码,按需选择

//---------------------- common ----------------------//

// 工具库: 库地址存储于 dp 在数据页面全局共享, dp 在页面加载后才有值
function loadAliworkSDK(ctx = window.LeGao.getContext()) {
  const src = ctx.dp.getValue("mjs_LIB");
  const script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.setAttribute("src", src);
  document.body.appendChild(script);
  script.onload = () => _mjsOnload(ctx);
}

//---------------------- private ----------------------//

// 加载即调用方法请在此处进行调用
async function _mjsOnload(ctx) {
  mjs.aliworkInitParams()
  // 效验操作组权限:提交态
  if (mjs._checkSubmitEnv()) { }
}

//【3.红色都是需要匹配的】明细查询和赋值
async function _queryAndUpdateCompData(ctx) {
  //【3.1.多条件查询】表单查询条件:src 来源表条件组件Id,cur 当前表条件组件ID,def 默认值优先级低于来源表数据
  const conditions = [{
    src: "textField_kfnjmfq2",
    cur: "selectField_kfnjp1cu",
    def: ""
  }];
  const resList = await mjs._queryFormOrProcess(ctx, { formId: "FORM-JHYJNJSVPXGLZXSE43HQV9M8XE7U2UHXM00JKB3", /** 数据来源表Id */ conditions, compId_tip: "selectField_kfnjp1cu", /** 非必填:报错的提示到输入框,可阻断提交 */ })
  //【3.2.1.多明细更新】明细组件Id映射表: src 来源明细表内组件ID,cur 当前明细表内组件ID,def 默认值优先级低于来源表数据
  const props1 = [{
    // 名称
    src: "textField_kfnjmfq4",
    cur: "selectField_kkny9ed5",
  },];
  mjs._updateCompDetailFromDetail(ctx, { resList, props: props1, compId_detail_src: "tableField_kfnjmfq3", /** 来源表明细组件Id */ compId_detail_cur: "tableField_kfnjmfq3" /** 当前明细的compId */ }, { funcFilter: null, /** 过滤方法条件:detail => detail["textField_kfnjmfq4"] == "条件" */ })
  //【3.2.2.多明细更新】明细组件Id映射表: src 来源明细表内组件ID,cur 当前明细表内组件ID,def 默认值优先级低于来源表数据
  const props2 = [{
    // 名称
    src: "textField_kfnjmfq4",
    cur: "textField_kknt6uqk",
  },];
  mjs._updateCompDetailFromDetail(ctx, { resList, props: props2, compId_detail_src: "tableField_kfnjmfq3", /** 来源表明细组件Id */ compId_detail_cur: "tableField_kknt6uqo" /** 当前明细的compId */ }, { funcFilter: null, /** 过滤方法条件:detail => detail["compId"] == "条件" */ })
  //【3.3.主表更新】组件Id映射表: src 来源表内组件ID,cur 当前表内组件ID,def 默认值优先级低于来源表数据
  const mains1 = [{
    // 主表赋值1
    src: "textField_kfnjmfq2",
    cur: "textField_kkoslg5n",
  },];
  mjs._updateCompMainFromMain(ctx, { resList, mains: mains1 })

  //【3.4.明细加载主表】组件Id映射表: src 来源表内组件ID,cur 当前表内明细组件ID,def 默认值优先级低于来源表数据
  const mains2 = [{
    // 主表赋值1
    src: "textField_kfnjmfq2",
    cur: "textField_kkou7cb4",
  },];
  mjs._updateCompDetailFromMain(ctx, { resList, props: mains2, compId_detail_cur: "tableField_kkou7cb3" /** 当前明细的compId */ }, { funcFilter: null, /** 过滤方法条件:main => main["compId"] == "条件" */ })
}

//---------------------- event ----------------------//

// 【1.将事件绑定到页面】页面节点加载渲染完毕
export function didMount(ctx) {
  // 加载工具库: dp & 初始化
  loadAliworkSDK(ctx)
}

//---------------------- event ----------------------//

// 【2.将事件绑定到查询条件】当查询条件发生变更
export function onConditionChange(ctx) {
  // 匹配查询和赋值
  _queryAndUpdateCompData(ctx)
}

3.服务变更流程

服务可执行宜搭公有云接口文档所有服务,也可调用后台开发提供的接口服务

前言

若是单据页面,可直接提供高级公式执行更新操作。流程单据不支持高级公式,可通过服务来完成。变更发起者可以是流程也可以是单据

demo 页面,目前以流程实例更新为案例

配置

  • 接口地址:更新流程实例

  • 将接口地址参数配置到宜搭服务,配置路径:【平台管理】➜【服务注册】➜【新增服务】

    1. 类型选择:GETWAY
    2. url 相对地址:填写对应服务的地址,如流程更新文档为 /yida_vpc/process/updateInstance.json
    3. 参数列表:点击 增加参数 将文档上参数一一对应拷贝过来

      1. 注意每个参数填写完成点击右侧保存,点击确认保护不会自动保存
      2. 第一列 参数名 必须为文档参数名称,标签名(中文)可填写文档描述,标签名(英文)可填写参数名称
    4. 其余默认即可:名称自行取,建议不要使用特殊符号,在使用的时候通过名称下拉选择

从接口参数可知,我们更新实例是需要 实例 Id:processInstanceId 的,因此需要一个中间表将 ID 存储起来

  • 中间表:记录关键字段,如编号,审批状态,关联名称,实例 ID,余下主表数据可通过编号从原流程单据进行数据联动

  • 审批过滤:此处刚好实现了审批过滤功能,一般将审批状态记录为三种状态:0-可提交;1-审批中;2-已通过;3-已关闭

数据引用,审批过滤:通过数据联动过滤审批状态,下拉框数据过滤审批状态;将实例 ID 字段通过中间表编号关联到出实例 ID 进行储存,配置服务都需要通过实例 ID 进行操作

  • 原始表:添加公式在审批通过完成执行公式,将中间表关键信息进行写入

    1. 注意:页面配置公式只对提交和编辑有效,执行公式不会触发页面内的组件公式,也不会自动带入默认值。
    2. 所有值的修改都需要写入,所有值的变动都需要写入,因此此处要写入审批状态为 0【可提交】
  • 中间表:将所有字段设置为可写入,将页面隐藏,方便管理员补录\调整数据。

    1. 过滤逻辑为写入数据审批状态为 0,在被引用时过滤为 0 可选取
    2. 当被下游单据引用时通过单号:在开始节点将审批状态更新为 1【审批中】。在完成节点,通过时将审批状态更新为 2 【已通过】,完成节点拒绝、撤销\终止,将审批状态回退为 0【可提交】。当单子行程闭环,可在适当位置将审批状态更新为 3 【已关闭】
  • 变更表:建议将原始表 Schema 直接导入过来,删除不能变更的字段,或者保留,将变更字段设置为可编辑,其余为只读

    1. 所有主表字段,通过数据联动完成,单号关联可来自中间表,可自行添加变更状态管理
    2. 明细字段建议通过接口自动读取,详见【1.表间数据关联】;若无此条件,自行添加中间表处理,让用户执行下拉勾线联动
    3. 明细字段:服务对明细的操作是全量替换,为了简化操作,明细内的组件 ID 必须 要和原始表一致,方法可以是直接将原表通过 Schema 导入过来,也可以是直接复制原表明细组件,粘贴到变更表上
    4. 明细变更:添加一个多行输入框,将需要被修改的明细内组件设置为可操作,余下不可修改都为只读。将如下代码复制到 js 面板中,将需要变更的明细内组件设置添加 onDetailChange事件,传入 ctx,"当前明细组件 ID", "多行输入框 ID", 若传入 details 会优先使用不再去取明细组件值
// 用于明细更新后返回:兼容用户不修改情况下操作
mjs._assembleDetailForKeyValue(ctx, "", "textareaField_kis8c0n5", details)

// 用于明细内组件变更:兼容用户修改同步明细数据
mjs._assembleDetailForKeyValue(ctx, "tableField_kfnjmfq3", "textareaField_kis8c0n5")
  1. 在流程完成节点配置服务:在同意节点执行服务操作,选择关联操作,选择第三方服务,此处会下拉出现在宜搭平配置的服务的名称列表,选择对应的服务,会出现配置好的参数列表,左侧显示名称为服务配置中文名称

    1. userId:#{LOGINUSER}    ➜ 取当前登录人;
    2. 应用秘钥:在应用设置 ➜ 应用数据 ➜ 应用秘钥
    3. 应用编码:在应用设置 ➜ 应用数据 ➜ 应用编码
    4. 实例 ID:输入 # 号键后,会弹出当前页面所有字段选项,选择实例 ID 组件即可
    5. 更新表单数据:{"原始表组件ID":"#{当前表组件ID}","原始表组件ID":"#{当前表组件ID}"},一一对应,多个按照格式添加即可
    6. 更新表单数据【明细处理】:格式和 5 一致,_区别是当前明细组件 ID 不使用,使用格式化后的多行文本框的值,尤其要注意:多行文本框不要添加不要引号,被转义后服务会失败_,正确格式:"原始明细组件ID": #{多行文本框ID}
  2. 服务可查询执行日志:

    1. 日志地址:https://aliwork.com/alibaba/web/APP_TYPE/query/invoke/queryRecord.json%3FpageNo=1&pageSize=10 ,将 APP_TYPE 替换为需要查询的应用 Id 即可
    2. 查询方式:查询的应用是当前页面登录的企业宜搭账号,若不匹配会报无此应用
  3. 补充:

    1. 若需要更新的数据大,可使用 json 格式化,完成后复制到 更新表单数据
    2. 操作建议:先配置更新一个主表字段,跑通流程,再测试多个字段,最后再单独测试明细数据
  4. 三方服务

    1. 宜搭服务回调是单向的, 没有重试机制, 所以流程审批结束同意操作下需要记录状态
    2. 在页面内添加记录成功与失败状态的组件, 失败原因. 调用后端服务接口传入 #{formInstId}, 后台执行完成后调用宜搭更新接口会写执行状态

多选合并查询明细

demo 值多选查询表单或者流程:

  • 多选条件仅仅支持一个字段;
  • 以第一条查询为主数据, 合并明细;
  • 数据联动可能会异常.

明细关联详细使用方式详见 2.表间数据关联


//---------------------- common ----------------------//

// 工具库: 库地址存储于 dp 在数据页面全局共享, dp 在页面加载后才有值
function loadAliworkSDK(ctx = window.LeGao.getContext()) {
  const src = ctx.dp.getValue("mjs_LIB");
  const script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.setAttribute("src", src);
  document.body.appendChild(script);
  script.onload = () => _mjsOnload(ctx);
}

//---------------------- private ----------------------//

// 加载即调用方法请在此处进行调用
async function _mjsOnload(ctx) {
  mjs.aliworkInitParams()
  // 效验操作组权限:提交态
  if (mjs._checkSubmitEnv()) { }
}

//【3.红色都是需要匹配的】明细查询和赋值
async function _queryAndUpdateCompData(ctx) {
 //【3.1.多条件查询】表单查询条件:src 来源表条件组件Id,cur 当前表条件组件ID,def 默认值优先级低于来源表数据 - 多选条件仅仅支持一个字段; 以第一条查询为主数据, 合并明细; 数据联动可能会异常
  const conditions = [{
    src: "textField_kfnjmfq2",
    cur: "multiSelectField_klu9cmvv",
    def: ""
  }];
  const resList = await mjs._queryMultipleFormOrProcess(ctx, { formId: "FORM-JHYJNJSVPXGLZXSE43HQV9M8XE7U2UHXM00JKB3", /** 数据来源表Id */ conditions, compId_tip: "multiSelectField_klu9cmvv", /** 非必填:报错的提示到输入框,可阻断提交 */ compId_detail_src: "tableField_kfnjmfq3", /** 来源表明细组件Id */ })
  //【3.2.1.多明细更新】明细组件Id映射表: src 来源明细表内组件ID,cur 当前明细表内组件ID,def 默认值优先级低于来源表数据
  const props1 = [{
    // 名称
    src: "textField_kfnjmfq4",
    cur: "selectField_kkny9ed5",
  },
  {
    // 名称
    src: "textField_kfnjmfq4",
    cur: "textField_kfnjmfq4",
  },
  {
    // 数量
    src: "numberField_kfnjmfq5",
    cur: "numberField_kfnjmfq5",
    def: 0
  },
  {
    // 价格
    src: "numberField_kfnjmfq6",
    cur: "numberField_kfnjmfq6"
  },
  {
    // 小计
    src: "numberField_kfnjmfq7",
    cur: "numberField_kfnjmfq7"
  }];
  mjs._updateCompDetailFromDetail(ctx, { resList, props: props1, compId_detail_src: "tableField_kfnjmfq3", /** 来源表明细组件Id */ compId_detail_cur: "tableField_kfnjmfq3" /** 当前明细的compId */ }, { funcFilter: null, /** 过滤方法条件:detail => detail["textField_kfnjmfq4"] == "条件" */ })

}

//---------------------- event ----------------------//

// 【1.将事件绑定到页面】页面节点加载渲染完毕
export function didMount(ctx) {
  // 加载工具库: dp & 初始化
  loadAliworkSDK(ctx)
}

//---------------------- event ----------------------//

// 【2. 将事件绑定到查询条件】当查询条件发生变更
export function onMultipleConditionChange(ctx) {
  // 匹配查询和赋值
  _queryAndUpdateCompData(ctx)
}

update 2021-02-03 w3 ➜ update 2021-03-02 w2