> 工具库功能和使用手册   [牧语  配置型文档](https://aliwork.zitoo.com.cn/doc/manual.html)

mjs 开发型文档

宜搭工具库,宜搭 `webApi` 调用能力,集成钉钉 `Api` 接口能力,工具库,宜搭调用外部服务器能力,宜搭数据处理,... --- ### 前言 - 组件赋值:文本和按钮显示修改需要使用 `set("content", "")`,修改按钮图标 `set("iconName", "")`, 赋值使用 `setVal` - 配置分支条件发起审批后,看到的预览是分之前的,只有当节点走到了分支才会显示。分支条件需要使用数字输入框和单选/下拉输入框,不支持单行收入、多行输入等 - 若是在明细可通过 scope 获取到 state,执行 invokeValidate 方法验证表单,或是直接赋值操作. 若要取消报错提示, 可执行验证为 true 后, 再执行强制验证: `forceValid()` 可消失 - 表单验证自定义规则入参有 3:value, state, ctx。在其规则函数内不能提供 scope 获取到明细组件值,若需要使用 scope 需要声明为方法 - 人员搜索框组件 - 异步赋值人员搜索框,需要设置为对象类型,包含:label, key, avatar。 - 若是同步赋值人员搜索框,通过 employee 公式关联输入框,映射 userId 即可,若多个用集合 - 明细赋值优化:兼容明细下拉框明细赋值更新异常问题: 让明细表单早于下拉框出现 ``` detailComp.setCurrentTargetDisable(true); detailComp.mergeVal(details); detailComp.setCurrentTargetDisable(false); ``` - 组件的事件内, 入参可有 2: 1 个全局对象 ctx, 2 是当前组件的 fieldData:: 明细不支持, 没有值 ``` // 当明细个人业绩发生变更: 匹配结清情况 export function onScopeResultChange(ctx, { value }) { } ``` - 取值区别:cacheData 取缓存,下拉框 change 事件内取到的是上一次的值(代码赋值不会),建议使用 ` ctx.store.get("组件ID").getVal()` - 接口公共参数处理 - appType 可取 pageConfig.appType - userId 非管理员无权限,可使用宜搭公共管理员,`yida_pub_account` - 交互提示 1. 弹出框 ``` ctx.fn.dialog({ method: 'confirm', // 或confirm title: '当前是详情页编辑态', }); ``` 2. 提示框::::: scope 不能使用 setBehavior, 可以使用 invokeValidate, 不能使用 forceValid ``` // 冗余Toast提示方法 function _showMessage(msg, type = "success") { if (!msg) return const ctx = window.LeGao.getContext() ctx.fn.toast({ title: msg, type, }); } ``` - 判断当前流程页面位置 ``` const modeData = ctx.getInstanceData().flowData || {}; // 提交态: 非 详情态 || 单据详情页编辑态 & 流程审批态 if (!(modeData.viewMode || modeData.editMode)) return ``` - 交互提示 1. 弹出框 ``` ctx.fn.dialog({ method: 'confirm', // 或confirm title: '当前是详情页编辑态', }); ``` 2. 提示框::::: scope 不能使用 setBehavior, 不能使用 invokeValidate, 不能使用 forceValid ``` // 冗余Toast提示方法 function _showMessage(msg, type = "success") { if (!msg) return const ctx = window.LeGao.getContext() ctx.fn.toast({ title: msg, type, }); } ``` - 高级公式 - 使用高级公式,条件如涉及到当期表,则条件的首参必须是目标表字段:否则报:主条件参数错误 - 高级公式 crud:可执行明细插入明细,在关联审批流时。不能同时操作多个明细,或明细和明细外组件 - 常用公式 - 由时间戳生成编号 `CONCATENATE("PRO",LEFT(TIMESTAMP(SYSTIME()),10))`, `CONCATENATE("COC",TEXT(TODAY(),"yyyyMMddHHmmSS"))` - 日期组件默认值:`TIMESTAMP(SYSTIME())` - 映射人员搜索框人员信息: `USERFIELD(人员搜索框,"userId")` -- `name`; 获取部门: `DEPTNAME(人员搜索框)` -- ### 集成 - 前言:使用工具库通过 `mjs` 对象进行调用,若需要在加载即调用方法,请在 `_initTaskCount` 调用 - 引入:绑定宜搭 `didMount` 事件,调用 `loadAliworkSDK(ctx)` 方法加载依赖 - 说明:宜搭支持 `es6` `async` `await` 语法。_工具库所有有返回值的方法都会返回 `Promise`_ ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _mjsOnload(ctx); } loadAliworkSDK(window.LeGao.getContext()) //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 function _mjsOnload(ctx) { // .... } //---------------------- event ----------------------// // 页面加载,载入工具库 export function didMount(ctx) { //loadAliworkSDK(ctx) } ``` - 明细查询标准接口和代码 ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/sampleEnginnering/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _mjsOnload(ctx); } loadAliworkSDK(window.LeGao.getContext()) // 载入工具库 //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 async function _mjsOnload(ctx) { // ... } // 重置明细数据::当前明细组件Id,明细组件对照表Id集合 function _resetDetailData(ctx) { const compDetail = ctx.store.get("tableField_kewa74uk") const details = compDetail.getData().fieldData.value details.forEach(row => propProduction.forEach(prop => row[prop.cur] = { fieldData: { value: "" } })) compDetail.mergeVal(details) } // 查询关联的合同表单的产品明细::当前明细组件Id,过滤条件,来源表Id,下拉框组件对象,来源表明细Id,明细组件对照表Id集合 async function _queryContractDetail(ctx, condition, comp) { const compDetail = ctx.store.get("tableField_kewa74uk") compDetail.setCurrentTargetDisable(true); // 只能查询当前formId下的表单字段 const conditionList = [{ fieldName: "selectField_kf0jdry4", value: condition }] const appType = pageConfig.appType const userId = loginUser.userId const res = await mjs.aliworkTheDynamicSubsidiary("/form/select", { appType, userId, formId: 'FORM-YSA66KC16Z5JALSJWT97I0WZHXRU2CYGUGWEKC', conditionList }).catch(() => []) // 容错 && 提示 const isErr = res.list.length comp.invokeValidate(isErr, "合同数据查询失败") comp.forceValid() if (!isErr) return // 更新明细 const form = res.list[0].formData const details = form["tableField_kewa74uk"].map(detail => { return propProduction.reduce((row, prop) => { const value = prop.src ? detail[prop.src] : "" row[prop.cur] = { fieldData: { value } } return row }, {}) }) setTimeout(() => compDetail.mergeVal(details)) // 赋值不能及时更新 compDetail.setCurrentTargetDisable(false); } //---------------------- source ----------------------// const propProduction = [{ // 产品名称 src: "selectField_kewa74uo", cur: "selectField_kewa74uo" }] //---------------------- event ----------------------// // 页面节点加载渲染完毕 export function didMount(ctx) { // ... } // 当合同编号发生变更 export function onContractChange(ctx) { _resetDetailData(ctx) const comp = ctx.store.get("selectField_kf0n0xsl") const condition = comp.getData().fieldData.value.split("-")[0] if (condition) _queryContractDetail(ctx, condition, comp) } ``` - 判断当前流程页面位置 ``` // 提交态: 非 详情态 || 单据详情页编辑态 & 流程审批态 const modeData = ctx.getInstanceData().flowData || {}; if (!(modeData.viewMode || modeData.editMode)) onStaffChange(ctx, loginUser.userId) ``` ### 钉钉 Api [钉钉 JSAPI 调试页面](https://wsdebug.dingtalk.com/)。**PC 端可能无法使用,钉钉打开宜搭默认会跳转外部浏览器** 所有钉钉接口都支持集成 ⇨ 弹出框,设备信息,日历时间选择,导航,开启刷新效果,扫一扫,存储,地图,电话,发钉消息,通讯录选人,釘盘,音视频接口,视频会议,支付,屏幕旋转,.... 1. 显示加载 loading: `mjs.showLoading()`. 不会自动关闭, 请在合适地方调用关闭, 或通过定时器完成 `setTimeout(() => mjs.hideLoading(), 2000)` 2. 关闭加载 loading: `mjs.hideLoading()` 3. 显示提示 Toast 1. [入参详见](https://ding-doc.dingtalk.com/doc#/dev/oo98ye/6pwsuy) 2. `mjs.showMessageToast()`. 默认 2s 后消失,若持续可见,传入对象属性 `duration` 为 0 即可;`message` 为空会被忽略 4. 获取当前位置信息:`mjs.getLocation()` -- ### 工具库 工具库 1. 获取随机数: `getRandomNumber(count = 1, max = 999, min = 1)` 2. 导入明细组件: 在 `_mjsOnload` 中调用: 上传组件 id 如 `fileReader`, 读取上传模板的 sheet 名称 如 `Sheet1`, 得到格式化后数据的回调, 设置明细数据源 ``` mjs.createElementUpload("fileReader", "Sheet1", function (details) { // 数据回调更新当前明细组件 ctx.store.get('tableField_kaxke4k9').mergeVal(details); }) ``` 3.货币精确计算:`const clac = mjs.calcLib()`, [使用详见](https://www.npmjs.com/package/number-precision) 3. 时间格式化 4. 获取汉字首字符 `getCaptureUpper` 5. 公式 - 避免单号重复,公式可用 yyyyMMddHHmmssSS,若太长,可用 yyMMddHHmmss -- ### 宜搭 Api 1. 关于下拉组件 1. 关于下拉单选:在非明细内,通过数据关联或代码赋值,即使未匹配到下拉选项,可以正常显示(明细内必须命中下拉选项):: 若需要能匹配, 提前创建组件占位, 可配合明细组件可用状态属性使用 2. 关于下拉多选:下拉多选不支持默认值数据联动,只能联动其下拉选项,联动结果为下拉选项是上一层选择的值。默认值可通过代码复制,无论是否在明细组件内,都不需要命中选项直接赋值 2. 关于人员搜索框: 若多选使用集合即可 1. 同步:人员框通过 employee 关联输入框, 在 didMount 赋值 userId,即在公式响应前赋值 2. 异步:因宜搭没有获取主管公式,通过钉钉调用后,写入人员搜索框,数据类型符合组件格式 3. 将宜搭添加到微应用入口的说明: 1. 在地址后添加 `&corpid=dingebe19bcf228f85ec35c2f4657eb6378f&dd_addcookie=true`, 实现钉钉跳转宜搭免登 2. 添加 `dd_addcookie=true` 后宜搭默认通过外部浏览器打开, 只保留 `corpId` 也能实现免登, 且 PC 端在钉钉内部打开: _可能宜搭对钉钉的适配有些小问题_ 3. 若存在重定向, 需要在 `didMount` 处理, 否则免登会失效 4. 调用网络请求前, 需要 `appType` 和 `userId` 1. 关于 `userId`: 若页面不显示人员, 可通过人员选择框或输入框组件绑定当前人员公式, 放到一个隐藏的容器中获取 (_该组件隐藏后不能后不能获取其值_): 若是动态选择需要 `setTimeout` 来获取 2. 关于 `appType`: 即当前应用的 `Id`, 配置在 `DataPool 数据池` 并全页面共享. 通过 `const appType = ctx.dp.getValue("appType")` 获取. 也可通过上传组件获取, _该组件可直接隐藏_ 3. 关于 `setBehavior`, 代码设置优先级高于权限配置, 因此若设置了 `NORMAL`, 则都会可见. _按钮不支持配置状态, 只要配置了就会在数据页面上展示_ ``` // 加载即调用方法请在此处进行调用 function _mjsOnload(ctx) { // 配置单据数据初始化 const queryForm = async function (userId) { // ... 私有且页面加载即发生的请求 } // 页面切换输入框会丢失,若存在userd,无需定时器延迟兼容,提升加载速度 const userId = sessionStorage.getItem("USER_ID") if (userId) { queryForm(userId) } else { setTimeout(() => { // 页面切换输入框会丢失,若存在userd,无需定时器延迟兼容,提升加载速度 const state = ctx.store.get('employeeField_k9u4zopg') userId = state.cacheData.fieldData.value[0].key sessionStorage.setItem("USER_ID", userId) queryForm(userId) }, 200) } } ``` 5. 数据查询不能使用文本框::偶现,可能是页面通过 schema 导入所致,通过下拉框映射编码可以查询到(下拉框赋值不知道默认值,赋值延迟 1s 处理,页面加载公式关联 Id 为空) ``` // 下拉框赋值不知道默认值,赋值延迟 1s 处理,页面加载公式关联 Id 为空: 数据查询不能使用文本框::偶现,可能是页面通过 schema 导入所致 setTimeout(() => { const code = ctx.store.getData("textField_kccqtl25").fieldData.value ctx.store.get("selectField_kf0jdry4").setVal(code) }, 1000) ``` 6. 动态设置明细组件 ``` // 采购明细请求数据 function _changePurchaseDetail(ctx, count) { const detail = { textField_k9mi4iny: { // 当前明细组件下子组件compId fieldData: { value: '物料001', } }, textField_ka3ajelw: { fieldData: { value: "称重", } }, numberField_k9mi4io0: { fieldData: { value: "300", } }, textField_k9mi4inx: { fieldData: { value: "千克", } }, numberField_k9mi4inz: { fieldData: { value: 10, } } }; // 明细赋值优化 const detailComp = ctx.store.get('tableField_ka3ajelv'); detailComp.setCurrentTargetDisable(true); detailComp.mergeVal(Array(Number(count)).fill(detail)); detailComp.setCurrentTargetDisable(false); } ``` 7. 明细赋值优化:兼容明细下拉框明细赋值更新异常问题: 让明细表单早于下拉框出现 ``` // 明细赋值优化:兼容明细下拉框明细赋值更新异常问题: 让明细表单早于下拉框出现 function _optimizeDetailComponent(state, details, count = 10) { if (!state) return if (!details) { // 明细组件赋值优化 state.setCurrentTargetDisable(true); state.mergeVal(Array(count).fill({})); } else { state.mergeVal(details); state.setCurrentTargetDisable(false); } } ``` 8. 动态设置下拉框组件: 下拉框 `value` 不支持复杂的数据类型. 但对象支持添加属性 - 「如意多部门切换关联审批人」 ``` // 采购申请请求数据 function _loadPurchaseApply (ctx) { const options = [ { text: '项目 004', value: 4, }, { text: '项目 001', value: 1 }, { text: '项目 007', value: 7 } ] ctx.store.get('selectField_k9mi4inr').set('options', options); } ``` 9. 设置数据源和行为 ``` // 删除测试 export function onClickDelete(ctx) { console.log("获取当前页面的唯一标识,即formUuid.", ctx.getCurrentPageId()) console.log("获取当前页面的数据池(DataPool).", ctx.getDataPool()) console.log("根据组件的fieldId,返回实际页面上的组件实例引用.", ctx.getComponentInstance("button_ka3ajelx")) // 隐藏操作:不支持直接删除 ctx.store.get('button_ka3ajelx').set('behavior', { fieldBehavior: 'HIDDEN' }) const state = ctx.store.get('selectField_k9mi4ins') state.setVal('') // 清空隐藏 state.set('behavior', { fieldBehavior: 'HIDDEN' }) ctx.store.get('selectField_k9mi4inq').setVal('请选择项目') } ``` 10. 采购订单案例: 1. 关联关系: 采购申请 `项目字段` 关联项目表单中的 `项目名称和项目编号`, 采购订单的 `项目名称` 关联采购申请中的 `项目名称`. 2. 操作项目: 当选择项目名称下拉框, 后台查询所选项目下的所有采购申请(**未做审批过滤**). 查询采购将采购申请下拉框置为 `NORMAL` 可用状态, _并更新采购申请下拉框以及其对应明细数据_ 3. 操作采购: 当选择采购申请下拉框时, 在 `change` 事件内, 将其明细数据填充到明细组件. _项目修改, 清除, 或采购清除重置采购下拉框和明细数据_ 4. _备注说明:_ 1. 表单关联仅会关联选择字段, 且会和其 `组件Id`绑定, **组件删改导致 Id 变更需要维护数据源** 2. 查询支持过滤条件, **条件和组件 id 要进行绑定, 且只能查询当前 formId 下的表单字段** 5. 使用说明: 将 `event` 分割线下事件进行绑定, 将页面中对应的 `组件Id` 更新. _宜搭是表单的值是通过 `组件Id`绑定, 取关联表单在原表单拷贝最合适_ ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/sampleEnginnering/mjs.min.js"; 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 _queryDetail(ctx, condition) { // 只能查询当前formId下的表单字段 const conditionList = [{ fieldName: "selectField_k9tw8gaq", value: condition } ] const appType = ctx.dp.getValue("appType") // 全局配置在数据池,避免通过上传组件获取 const state = ctx.store.get('employeeField_kaotctsb') const userId = state.cacheData.fieldData.value[0].key // 查询采购申请表单关联的明细 const res = await mjs.aliworkTheDynamicSubsidiary("/form/select", { appType, userId, formId: 'FORM-RM966M919ODFEKPD5USBJBKG4R3022T98WT9K9G4', conditionList }) // 设置采购申请下拉框可用,并设置下拉数据源 ctx.store.get('selectField_k9mi4inr').set('behavior', { fieldBehavior: 'NORMAL' }) const options = res.list.map((item, index) => { const form = item.formData const select = form["textField_kaorkyrr"] + '-' + form["textField_kaoqmj6i"] const details = form["tableField_k9tw8gar"].map(detail => { return { textField_k9mi4iny: { fieldData: { value: detail["selectField_k9xury38"], } }, textField_kaq54olm: { fieldData: { value: detail["textField_k9tw8gat"], } }, numberField_k9mi4io0: { fieldData: { value: undefined, } }, numberField_k9mi4inz: { fieldData: { value: detail["numberField_k9tw8gav"], } }, textField_k9mi4inx: { fieldData: { value: detail["textField_k9xury39"], } } } }) return { text: select, value: index, // 下拉框value不支持复杂的数据类型:但支持添加属性 details: details } }) ctx.store.get('selectField_k9mi4inr').set('options', options); } // 重置选择状态和数据 function _resetPurchaseAndDetail(ctx, clearOptions) { ctx.store.get('tableField_kaq54oll').mergeVal([]); const state = ctx.store.get('selectField_k9mi4inr') state.setVal("") if (clearOptions) state.set('options', []); } //---------------------- event ----------------------// // 页面加载,载入工具库 export function didMount(ctx) { loadAliworkSDK(ctx) } // 项目下拉框:关联采购申请表单,选择设置采购申请下拉框可用,并处理数据 export function onProjectChange(ctx) { _resetPurchaseAndDetail(ctx, true) const selected = ctx.store.getData("selectField_k9mi4inq").fieldData.value if (selected) _queryDetail(ctx, selected) else ctx.store.get('selectField_k9mi4inr').set('behavior', { fieldBehavior: 'DISABLED' }) } // 采购申请下拉框:将格式好数据设置到明细 export function onPurchaseChange(ctx) { const state = ctx.store.getData("selectField_k9mi4inr") if (!state.fieldData.value) { _resetPurchaseAndDetail(ctx) return } const details = state.options[state.fieldData.value].details ctx.store.get('tableField_kaq54oll').mergeVal(details); } ``` 11. 采购入库: 关联采购订单表单, 逻辑代码镜像 `5. 采购订单案例` ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/sampleEnginnering/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _initTaskCount(ctx); } //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 async function _initTaskCount(ctx) { // .... console.log("mjs", mjs) } // 查询采购申请表单关联的明细 async function _queryDetail(ctx, condition) { // 只能查询当前formId下的表单字段 const conditionList = [{ fieldName: "selectField_k9tw8gaq", value: condition }] const appType = ctx.dp.getValue("appType") // 全局配置在数据池,避免通过上传组件获取 const state = ctx.store.get('employeeField_k9rsqfip') const userId = state.cacheData.fieldData.value[0].key // 查询采购申请表单关联的明细 const res = await mjs.aliworkTheDynamicSubsidiary("/form/select", { appType, userId, formId: 'FORM-W5666U816ODFAUQBY4R7VZAJJL9T1KSD4IM9K151', conditionList }) // 设置采购申请下拉框可用,并设置下拉数据源 ctx.store.get('selectField_k9mi4inr').set('behavior', { fieldBehavior: 'NORMAL' }) const options = res.list.map((item, index) => { const form = item.formData const select = form["employeeField_kaotctsb"] + "-" + form["textField_kaqfkxm5"] const details = form["tableField_kaq54oll"].map(detail => { return { textField_kaqd9y6k: { fieldData: { value: detail["textField_k9mi4iny"], } }, textField_kaqe45de: { fieldData: { value: detail["textField_kaq54olm"], } }, textField_kaqd9y6o: { fieldData: { value: detail["numberField_k9mi4io0"], } }, numberField_kaqd9y6l: { fieldData: { value: detail["numberField_k9mi4inz"], } }, textField_kaqd9y6m: { fieldData: { value: detail["textField_k9mi4inx"], } } } }) return { text: select, value: index, // 下拉框value不支持复杂的数据类型 details: details, supplier: form["selectField_k9mi4ins"] // 供应商 } }) ctx.store.get('selectField_k9mi4inr').set('options', options); } // 重置选择状态和数据 function _resetPurchaseAndDetail(ctx, clearOptions) { ctx.store.get('tableField_kaqd9y6n').mergeVal([]); const state = ctx.store.get('selectField_k9mi4inr') state.setVal("") if (clearOptions) state.set('options', []); } //---------------------- event ----------------------// // 页面加载,载入工具库 export function didMount(ctx) { loadAliworkSDK(ctx) } // 项目下拉框:关联采购申请表单,选择设置采购申请下拉框可用,并处理数据 export function onProjectChange(ctx) { _resetPurchaseAndDetail(ctx, true) const selected = ctx.store.getData("selectField_k9mi4inq").fieldData.value if (selected) _queryDetail(ctx, selected) else ctx.store.get('selectField_k9mi4inr').set('behavior', { fieldBehavior: 'DISABLED' }) } // 采购申请下拉框:将格式好数据设置到明细 export function onPurchaseChange(ctx) { const state = ctx.store.getData("selectField_k9mi4inr") if (!state.fieldData.value) { _resetPurchaseAndDetail(ctx) return } const option = state.options[state.fieldData.value] ctx.store.get('selectField_k9mi4ins').setVal(option.supplier || "") ctx.store.get('tableField_kaqd9y6n').mergeVal(option.details); } ``` 12.  通过 `Excel` 导入明细组件 ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _initTaskCount(ctx); } //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 async function _initTaskCount(ctx) { // .... mjs.createElementUpload("fileReader", "Sheet1", function (details) { // 数据回调更新当前明细组件 console.log(details) ctx.store.get('tableField_kaxke4k9').mergeVal(details); console.log("detail Id", ctx.store.get('tableField_kaxke4k9')) }) } //---------------------- event ----------------------// // 页面节点加载渲染完毕 export function didMount(ctx) { loadAliworkSDK(ctx) } // 响应Excel上传事件 export function onUploadClick(ctx) { document.getElementById('fileReader').click(); } ``` 13. 更新明细组件宽度: 传入组件 class `.node_k9z1uvrr`, 在明细组件标签上; 变更宽度建议用百分比, 大于 `100%` ``` // 设置明细组件宽度: 将明细拖入容器,设置其overflow scroll function setDetaiComplWidth(className, width) { // setDetaiComplWidth(".node_k9z1uvrr", "130%") 明细组件的唯一id const elem = document.querySelector(className); if (!elem) return elem.style['max-width'] = width elem.style.width = width } ``` 14. 获取钉钉主管列表接口, 兼容宜搭数据关联: 人员搜索框不能得到其值, 通过公式关联到输入框后读取输入框 ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/ruyi/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _mjsOnload(ctx); } //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 function _mjsOnload(ctx) { // .... } //---------------------- event ----------------------// // 页面加载,载入工具库 export function didMount(ctx) { loadAliworkSDK(ctx) } // 报销人变更 let userIdT = '' export function onStaffChange(ctx) { // 清空历史数据 const deptComp = ctx.store.get('selectField_kc3ixvdp') deptComp.setVal(""); deptComp.set('options', []); deptComp.setBehavior("DISABLED") ctx.store.get("employeeField_kbrl75yp").setVal([]) ctx.store.get("employeeField_kbrp6uv1").setVal([]) // 拉取报销人对应主管列表 const getManager = async (userId) => { const res = await mjs.ddingAddressBook(userId); const obj = JSON.parse(res.data); // 部门列表 const options = [] const departs = Object.keys(obj.deptInfo) departs.forEach((key, index) => { // 遍历审批人 const arr = [] obj.parentDpData[key].forEach((item) => { if (!item || item.userid === userId) return true // 空 || 当前部门主管 if (!item.errcode) arr.push({ avatar: item.avatar, key: item.userid, label: `(${item.name})${item.userid}` }); }); // 报销人所属部门单选选项预设 options.push({ text: obj.deptInfo[key], value: index, approve: arr, }) if (arr.length) deptComp.setBehavior("NORMAL") }) // 若仅属于一个部门直接赋值 deptComp.set('options', options); if (options.length === 1 && options[0].approve.length) { deptComp.setVal(0); onDepartChange(ctx) } } let timer = setInterval(() => { const userId = ctx.store.get('textField_kbrktjhc').cacheData.fieldData.value // 宜搭组件关联不支持置空,添加变量记录 if (userId && userId !== userIdT) { userIdT = userId clearInterval(timer) timer = null getManager(userId) } }, 100) } // 当报销人所属部门修改后 export function onDepartChange(ctx) { const state = ctx.store.get("selectField_kc3ixvdp").getData() const arr = state.options[Number(state.fieldData.value)].approve // 分管董事 if (arr.length) ctx.store.get("employeeField_kbrp6uv1").setVal([arr.pop()]) // 上级主管列表 ctx.store.get("employeeField_kbrl75yp").setVal(arr) } ``` 15. 明细组件关联状态, 绑定到审批流程配置内 ``` // 当流程变更:需要董事审批 export function onProcessChange(ctx) { const details = ctx.store.getData("tableField_k9z1uvs2").fieldData.value const condition = {'公关': -1, "年检/软件服务费/律师费等/质量检测费": -1, "门店试吃费/新品研发": 300, "劳保用品": 500, "召开会议发生的场地餐费住宿费等": 500, "快递费/办公用品": 500, "办事处固话宽带": 500, "打车(出差发生除外)": 40, "业务招待费": -1, "消防材料/小型工具器具/直营店自购辅料": 500, "直营店税金": -1, "财产保险/雇主责任险/食品安全险": 1000, "劳务中介费/招聘平台": 1000, "垃圾清理保洁/花木租赁/绿化费/泔水处理": 500, "书籍资料/继续教育/新员工培训": 500, "奖金": -1, "食堂餐费": -1, "厂房修缮": 500, "日常修理费": 500, "视频拍摄/百度竞价/搜索引擎/网络推广": 1000, "总部-宣传物料/外卖平台补贴": -1, "团建/节日发放福利/加班餐费/员工探视": -1} const approve = Object.keys(condition) details.forEach(item => { const pro = item["selectField_k9z1uvsq"].fieldData.value const amm = mjs.calcLib().times(Number(item["textField_k9m12fzg"].fieldData.value), Number(item["numberField_k9klpsw2"].fieldData.value)) // 计算金额 // 是否需要一级主管审批状态值 const app = (approve.includes(pro) && amm > condition[pro]) item["numberField_kbyu00rh"] = { fieldData: { value: Number(app) } } // 重置状态添加响应式 }) ctx.store.get("tableField_k9z1uvs2").mergeVal(details) } ``` 16. 如意代报销流程 ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/ruyi/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _initTaskCount(ctx); } //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 function _initTaskCount(ctx) { onStaffChange(ctx, loginUser.userId) } //---------------------- event ----------------------// // 页面加载,载入工具库 export function didMount(ctx) { loadAliworkSDK(ctx) } // 报销人变更 let userIdT = '' export function onStaffChange(ctx, userId) { // 清空历史数据 const deptComp = ctx.store.get('selectField_kc3ixvdp') if (deptComp.getData().fieldData.value) deptComp.setVal(""); deptComp.set('options', []); ctx.store.get("employeeField_kbrl75yp").setVal([]) ctx.store.get("employeeField_kbrp6uv1").setVal([]) // 拉取报销人对应主管列表 const getManager = async (userId) => { const res = await mjs.ddingAddressBook(userId); const obj = JSON.parse(res.data); // 部门列表 const options = [] const departs = Object.keys(obj.deptInfo) departs.forEach((key, index) => { // 遍历审批人 const arr = [] obj.parentDpData[key].forEach((item) => { if (!item || item.userid === userId) return true // 空 || 当前部门主管 if (!item.errcode) arr.push({ avatar: item.avatar, key: item.userid, label: item.name }); }); // 报销人所属部门单选选项预设 const name = obj.deptInfo[key] options.push({ text: name, value: name, approve: arr, }) }) // 若仅属于一个部门直接赋值 deptComp.set('options', options); if (options.length === 1 && options[0].approve.length) { deptComp.setVal(options[0].value); onDepartChange(ctx) } } if (!userId) userId = ctx.store.getData("employeeField_kc8z8awp"),fieldData.value[0].key getManager(userId) } // 当报销人所属部门修改后 export function onDepartChange(ctx) { const state = ctx.store.get("selectField_kc3ixvdp").getData() const arr = (state.options.find(item => state.fieldData.value == item.value)).approve // 分管董事 if (arr.length) ctx.store.get("employeeField_kbrp6uv1").setVal([arr.pop()]) // 上级主管列表 ctx.store.get("employeeField_kbrl75yp").setVal(arr) } ``` 17. ... ``` //---------------------- common ----------------------// // 工具库 function loadAliworkSDK(ctx) { const src = "https://aliwork.zitoo.com.cn/sampleEnginnering/mjs.min.js"; const script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute("src", src); document.body.appendChild(script); script.onload = () => _mjsOnload(ctx); } loadAliworkSDK(window.LeGao.getContext()) // 载入工具库 //---------------------- private ----------------------// // 加载即调用方法请在此处进行调用 async function _mjsOnload(ctx) { // ... } // 设置明细组件宽度: 将明细拖入容器,设置其overflow scroll function setDetaiComplWidth(className, width) { // setDetaiComplWidth(".node_k9z1uvrr", "130%") 明细组件的唯一id const elem = document.querySelector(className); if (!elem) return elem.style['max-width'] = width elem.style.width = width } // 重置明细数据::当前明细组件Id,明细组件对照表Id集合 function _resetDetailData(ctx) { const compDetail = ctx.store.get("tableField_kewa74uk") const details = compDetail.getData().fieldData.value details.forEach(row => propProduction.forEach(prop => row[prop.cur] = { fieldData: { value: prop.def } })) compDetail.mergeVal(details) } // 查询关联的合同表单的产品明细::当前明细组件Id,过滤条件,来源表Id,下拉框组件对象,来源表明细Id,明细组件对照表Id集合 async function _queryContractDetail(ctx, condition, comp) { const compDetail = ctx.store.get("tableField_kewa74uk") compDetail.setCurrentTargetDisable(true); // 只能查询当前formId下的表单字段 const conditionList = [{ fieldName: "textField_kf0n0xsh", value: condition }] const appType = pageConfig.appType const userId = loginUser.userId const res = await mjs.aliworkTheDynamicSubsidiary("/form/select", { appType, userId, formId: 'FORM-YSA66KC1626J1EYY0FUWD9JXGNRL2SM0CHWEK23', conditionList }).catch(() => []) // 容错 && 提示 const isErr = res.list.length comp.invokeValidate(isErr, "采购计划查询失败") comp.forceValid() if (!isErr) return // 更新明细 const form = res.list[0].formData const details = form["tableField_kewa74uk"].map(detail => { return propProduction.reduce((row, prop) => { const value = prop.src ? detail[prop.src] : prop.def row[prop.cur] = { fieldData: { value } } return row }, {}) }) setTimeout(() => compDetail.mergeVal(details)) // 赋值不能及时更新 compDetail.setCurrentTargetDisable(false); DETAILS_PRODUCTION = details // 记录供应商修改缓存数据 } //---------------------- source ----------------------// const propProduction = [{ // 产品站点 src: "selectField_kf57ylzr", cur: "selectField_kf57ylzr", def: "" }, { // 产品站点编号 src: "textField_kewa74uq", cur: "textField_kewa74uq" }, { // 产品模块 src: "selectField_kewa74uo", cur: "selectField_kewa74uo" }, { // 产品线 src: "selectField_kewa74up", cur: "selectField_kewa74up" }, { // 产品类型 src: "selectField_kf54yfkg", cur: "selectField_kf54yfkg" }, { // 规格 src: "textField_kewa74ur", cur: "textField_kewa74ur" }, { // 标准报价 src: "numberField_kewa74us", cur: "numberField_kewa74us" }, { // 折扣 src: "numberField_kewa74ut", cur: "numberField_kewa74ut" }, { // 售价 src: "numberField_kewa74uu", cur: "numberField_kewa74uu" }, { // 数量 src: "numberField_kewa74uv", cur: "numberField_kewa74uv" }, { // 单位 src: "selectField_kewa74ux", cur: "selectField_kewa74ux" }, { // 售价小计 src: "numberField_kewa74uy", cur: "numberField_kewa74uy" }, { // 备注 src: "textareaField_kexnujd0", cur: "textareaField_kexnujd0" }, { // 加密方式 src: "selectField_kexnujd5", cur: "selectField_kexnujd5" }, { // 产品模块 src: "multiSelectField_kewa74uz", cur: "multiSelectField_kewa74uz" }, { // 品牌 src: "textField_kexnujd1", cur: "textField_kexnujd1" }, { // 型号 src: "textField_kexnujd2", cur: "textField_kexnujd2" }, { // 供应商 src: "multiSelectField_kfai2kue", cur: "multiSelectField_kfai2kue" }, { // 采购价预计 src: "numberField_kf0n0xsm", cur: "numberField_kf0n0xsm" }, { // 状态 src: "selectField_kf0n0xsj", cur: "selectField_kf0n0xsj" }, { // 采购单价 src: "", cur: "numberField_kf0tqfzg" }, { // 采购折扣(%) src: "", cur: "numberField_kf0tqfzh" }, { // 采购总价 src: "", cur: "numberField_kf0tqfzi" }, { // 返佣比例 src: "", cur: "numberField_kf0tqfzl" }, { // 应返佣金额 src: "", cur: "numberField_kf0tqfzm" }, { // 回写下单供应商 src: "multiSelectField_kfai2kuf", cur: "multiSelectField_kfahy1nt" }] //---------------------- event ----------------------// // 页面节点加载渲染完毕 export function didMount(ctx) { // ... setDetaiComplWidth(".node_kewa74ti", "230%") } let DETAILS_PRODUCTION = [] // 当合同编号发生变更 export function onContractChange(ctx) { ctx.store.get("selectField_kf0tqfz0").setVal("") // 清空供应商 _resetDetailData(ctx) const comp = ctx.store.get("selectField_kf0tqfyx") const condition = comp.getData().fieldData.value.split("-")[0] if (condition) _queryContractDetail(ctx, condition, comp) } // 当供应商变更 export function onSupplierChange(ctx) { // 过滤相同供应商 const supplier = ctx.store.getData("selectField_kf0tqfz0").fieldData.value const detailsT = DETAILS_PRODUCTION.filter(detail => { // 多选过滤 const suppliers = detail["multiSelectField_kfai2kue"].fieldData.value || [] // 多选没有值,就没有这个字段,明细接口查询:可以被回写 let supplied = detail["multiSelectField_kfai2kuf"] supplied = supplied ? supplied.fieldData.value || [] : [] const isConfirm = detail["multiSelectField_kfai2kue"].fieldData.value.includes(supplier) && !supplied.includes(supplier) if (isConfirm) { // 记录选择供应商集合:不直接修改明细避免数据污染,新值记录 supplied.push(supplier) detail["multiSelectField_kfahy1nt"] = { fieldData: { value: supplied } } } return isConfirm }) ctx.store.get("tableField_kewa74uk").mergeVal(detailsT) } ``` - remark ``` 关于侧边栏和免登: 无侧边栏, 在设置分享复制访问地址, 没有免登, PC端不会跳出钉钉浏览器: https://www.aliwork.com/alibaba/web/APP_EE7IAJLY0UQRRJOPHMN3/inst/formSubmit.html?formUuid=FORM-UR566DD1G3MH5QGQ2OF9F9I8KXGW288GT2PCKD#/ 有侧边栏, 直接复制的有侧边栏的访问地址, 没有免登, PC端不会跳出钉钉浏览器: https://www.aliwork.com/alibaba/web/APP_EE7IAJLY0UQRRJOPHMN3/inst/homepage/#/FORM-UR566DD1G3MH5QGQ2OF9F9I8KXGW288GT2PCKD 无侧边栏, 在设置分享复制移动端访问地址, 有免登, PC端跳出钉钉在浏览器打开: https://www.aliwork.com/alibaba/web/APP_EE7IAJLY0UQRRJOPHMN3/inst/formSubmit.html?formUuid=FORM-UR566DD1G3MH5QGQ2OF9F9I8KXGW288GT2PCKD&corpid=dingebe19bcf228f85ec35c2f4657eb6378f&dd_addcookie=true 工作台4个任务和列表页面, 不能隐藏侧边栏 :: 免登追加corpid=xxx&dd_addcookie=true ```