> 工具库功能和使用手册   [牧语  开发文档](https://aliwork.zitoo.com.cn/mjs.html)

mjs 配置型文档

--- ## 宜搭公式 ### 常用公式 1. 日期格式为数值, 如 7 - 12 点不允许点餐: ``` OR(GT(VALUE(TEXT(DATE(TIMESTAMP(SYSTIME())),"HHmm")),1600),GT(700,VALUE(TEXT(DATE(TIMESTAMP(SYSTIME())),"HHmm")))) ``` 2. 获取天数差值:`DYAS(DATE(结束日期组件),DATE(开始日期组件))` 3. 由时间戳生成编号 `CONCATENATE("PRO",LEFT(TIMESTAMP(SYSTIME()),10))`, `CONCATENATE("COC",TEXT(TODAY(),"yyyyMMddHHmmSS"))` 4. 日期组件默认值:`TIMESTAMP(SYSTIME())` 5. 数据关联两个字段, 数据联动处理, 获取拼接字段的其中一个值:`ARRAYGET(SPLIT(​ 合同编号 ​,"-"), 1)` 6. 明细数据某一列不能重复验证: 自定义验证函数 - 不能使用 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 } ``` 7. 映射人员搜索框人员信息: `USERFIELD(人员搜索框,"userId")` -- `name`; 获取部门: `DEPTNAME(人员搜索框)` ### 高级公式 - 使用高级公式,条件如涉及到当期表,则条件的首参必须是目标表字段:否则报:主条件参数错误 - 高级公式 crud:可执行明细插入明细,在关联审批流时。不能同时操作多个明细,或明细和明细外组件 --- ## 2.表间数据关联 从一个表单或者流程页面,自动加载其它表单或者流程的明细数据,自动填充到当前页面指定组件内 ### 前言 两个准备工作,整个应用仅仅配置一次。**上线前请切换生产地址,通过数据源配置方案仅修改一次即可** - 提供应用的 code 和 secret:【应用设置】➜【应用数据】➜【应用编码】|【应用秘钥】 - 在数据源添加库地址,`mjs_LIB` 公共库地址: ### 效果 > [demo](https://www.aliwork.com/alibaba/web/APP_XZ180SDQ2TQ3UUB7KR2A/inst/formSubmit.html?formUuid=FORM-RM966M91I9MJ7RMQ0RKX6B6EN1I23L6ZOJNFKBA&corpid=dingebe19bcf228f85ec35c2f4657eb6378f&dd_addcookie=true) 页面 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](https://www.aliwork.com/alibaba/web/APP_XZ180SDQ2TQ3UUB7KR2A/admin/pageAppEdit.html?spm=a1z4e7.13467989.0.0.41821791ZVa3Wh#/form/process/FORM-JFYJZQEVMOVLZUIUVZE7VFJZON5P1B4L94QIK08/page?code=TPROC--JFYJZQEVMOVLZUIUVZE7VFJZON5P1B4L94QIK18&navUuid=FORM-JFYJZQEVMOVLZUIUVZE7VFJZON5P1B4L94QIK08&_k=hoakq3) 页面,**目前以流程实例更新为案例** ### 配置 - [接口地址:更新流程实例](https://www.yuque.com/yida-old/help/ihxi9r#r78nho) - 将接口地址参数配置到宜搭服务,配置路径:【平台管理】➜【服务注册】➜【新增服务】 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") ``` 5. 在流程完成节点配置服务:在同意节点执行服务操作,选择关联操作,选择第三方服务,此处会下拉出现在宜搭平配置的服务的名称列表,选择对应的服务,会出现配置好的参数列表,左侧显示名称为服务配置中文名称 1. userId:#{LOGINUSER}    ➜ 取当前登录人; 2. 应用秘钥:在应用设置 ➜ 应用数据 ➜ 应用秘钥 3. 应用编码:在应用设置 ➜ 应用数据 ➜ 应用编码 4. 实例 ID:输入 # 号键后,会弹出当前页面所有字段选项,选择实例 ID 组件即可 5. 更新表单数据:`{"原始表组件ID":"#{当前表组件ID}","原始表组件ID":"#{当前表组件ID}"}`,一一对应,多个按照格式添加即可 6. **更新表单数据【明细处理】:**格式和 **5** 一致,_区别是当前明细组件 ID 不使用,使用格式化后的多行文本框的值,**尤其要注意:多行文本框不要添加不要引号,被转义后服务会失败**_,正确格式:`"原始明细组件ID": #{多行文本框ID}` 6. 服务可查询执行日志: 1. 日志地址:`https://aliwork.com/alibaba/web/APP_TYPE/query/invoke/queryRecord.json%3FpageNo=1&pageSize=10` ,将 `APP_TYPE` 替换为需要查询的应用 Id 即可 2. 查询方式:查询的应用是当前页面登录的企业宜搭账号,若不匹配会报无此应用 7. 补充: 1. 若需要更新的数据大,可使用 [json 格式化](https://www.bejson.com/),完成后复制到 `更新表单数据` 2. 操作建议:先配置更新一个主表字段,跑通流程,再测试多个字段,最后再单独测试明细数据 8. 三方服务 1. 宜搭服务回调是单向的, 没有重试机制, 所以流程审批结束同意操作下需要记录状态 2. 在页面内添加记录成功与失败状态的组件, 失败原因. 调用后端服务接口传入 #{formInstId}, 后台执行完成后调用宜搭更新接口会写执行状态 --- ### 多选合并查询明细 [demo](https://www.aliwork.com/alibaba/web/APP_LJHV920D3CF3KNPRYN40/admin/pageAppEdit.html?spm=a1z4e7.13467989.0.0.bdcb6ddbakMjxp#/form/receipt/FORM-PFYJO8XU7G2OP1V63M57W66LM24D3H6L4AULKN6/page?navUuid=FORM-PFYJO8XU7G2OP1V63M57W66LM24D3H6L4AULKN6&_k=lxq5eu) 值多选查询表单或者流程: - 多选条件仅仅支持一个字段; - 以第一条查询为主数据, 合并明细; - 数据联动可能会异常. > 明细关联详细使用方式详见 [2.表间数据关联](https://www.yuque.com/gxg6w6/xg2yg3/txoqrm) ``` //---------------------- 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