1. 使用场景
在宜搭中简单的表单提交可以使用普通表单来实现,但是普通表单无法自定义表格样式。当我们需要复杂的表格样式并且进行提交时,我们应该如何实现呢?在宜搭中可以使用自定义页面进行开发,自定义页面有 JSX、HTML 组件,可以实现复杂的业务场景。那么此文档带大家一起来了解一下,如何配置自定义表格的提交和查看。
在宜搭中简单的表单提交可以使用普通表单来实现,但是普通表单无法自定义表格样式。当我们需要复杂的表格样式并且进行提交时,我们应该如何实现呢?在宜搭中可以使用自定义页面进行开发,自定义页面有 JSX、HTML 组件,可以实现复杂的业务场景。那么此文档带大家一起来了解一下,如何配置自定义表格的提交和查看。
数据依赖表单的作用:数据依赖表单用来存储自定义页面提交的数据。
要将自定义页面的数据通过接口传入到表单页面,需要获取到表单页面的唯一标识,需要注意的是手写签名组件不可以直接在接口传值,所以要使用单行文本做辅助。
图3.1 数据依赖表单
在链接内生成表格样式:https://www.tablesgenerator.com/html_tables#
备注:表格制作工具 TablesGenerator 是一个在线制作 LaTeX、HTML、Markdown 格式的表格代码工具,支持在表格中填充数据,修改字体/背景颜色,对齐方式等等。
图3.2-1 使用TablesGenerator
复制代码放入 JSX 中,JSX >> 编辑 JSX 代码 >> 代码复制粘贴
图3.2-2 绘制表格
将生成的样式复制到 JSX >> 样式 >> 源码编辑。根据需求,可以在源码编辑中自行更改样式。
图3.2-3 复制到JSX源码编辑
下述代码可以直接复制到源码编辑
/*JSX样式->源码编辑*/ .tg {border-collapse:collapse;border-spacing:0;width:100%} .tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; overflow:hidden;padding:10px 5px;word-break:normal;} .tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px; font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;} .tg .tg-34fe{background-color:#c0c0c0;border-color:inherit;text-align:center;vertical-align:top} .tg .tg-c3ow{border-color:inherit;text-align:center;vertical-align:top;} .next-form-item{ margin:0 }
获取组件标签 >> 定义属性 >> 渲染组件
图3.2-4 JSX渲染组件
后续需要复用属性,并且传值到接口去新增数据和查看数据,要使用变量数据源定义属性。
定义变量数据源 >> 将属性值替换成变量 >> 渲染组件
图3.2-5 设置变量数据源
在js面板中定义一个onchange方法,然后在JSX中使用this.onChange设置组件的onchange属性,作用是将组件值更新到变量数据源中并渲染。
图3.2-6 获取组件值更新变量数据源
下述代码可直接复制编辑JS面板内,注意:需要JSX组件的唯一标识。
export function onChange({ value }, index) { //console.log(value, index); //给 componentIds 变量数据源的 index 下标赋 value 值 this.state.componentIds[index] = value; this.$('JSX_kt9ikv55').forceUpdate(); }
下述代码可直接复制编辑JSX代码内。注意:要配置变量数据源,并更改唯一标识为依赖表单唯一标识。
//JSX代码 function render(me, state, data, ctx) { //将变量数据源引入到JSX中使用 const { radioDatas, componentIds, componentStatus } = this.state; return ( <div> <table class="tg"> <thead> <tr> <th class="tg-34fe" colspan="20">测试表格</th> </tr> </thead> <tbody> <tr> <td class="tg-c3ow" colspan="4">单选</td> <td class="tg-c3ow" colspan="6"><RadioField dataSource={radioDatas} value={componentIds.radioField_kt8hni6y} onChange={(value) => { this.onChange(value, 'radioField_kt8hni6y') }} behavior={componentStatus} /></td> <td class="tg-c3ow" colspan="4">日期</td> <td class="tg-c3ow" colspan="6"><DateField value={componentIds.dateField_kt8hni6z} onChange={(value) => { this.onChange(value, 'dateField_kt8hni6z') }} behavior={componentStatus} /></td> </tr> <tr> <td class="tg-c3ow" colspan="4">手写签名</td> <td class="tg-c3ow" colspan="6"><DigitalSignatureField useLastSignature={false} value={componentIds.textField_kt8i83vj} onChange={(value) => { this.onChange(value, 'textField_kt8i83vj') }} behavior={componentStatus} /></td> <td class="tg-c3ow" colspan="4">多行文本</td> <td class="tg-c3ow" colspan="6"><TextareaField placeholder={"请输入"} value={componentIds.textareaField_kt8hni71} onChange={(value) => { this.onChange(value, 'textareaField_kt8hni71') }} behavior={componentStatus} /></td> </tr> <tr> <td class="tg-c3ow" colspan="4">下拉单选</td> <td class="tg-c3ow" colspan="6"><SelectField dataSource={radioDatas} hasClear={true} value={componentIds.selectField_kt8hni72} onChange={(value) => { this.onChange(value, 'selectField_kt8hni72') }} behavior={componentStatus} /></td> <td class="tg-c3ow" colspan="4">数值</td> <td class="tg-c3ow" colspan="6"><NumberField value={componentIds.numberField_kt8hni73} onChange={(value) => { this.onChange(value, 'numberField_kt8hni73') }} behavior={componentStatus} /></td> </tr> <tr> <td class="tg-c3ow" colspan="4">单行文本</td> <td class="tg-c3ow" colspan="6"><TextField hasClear={true} placeholder={"请输入"} value={componentIds.textField_kt8hni74} onChange={(value) => { this.onChange(value, 'textField_kt8hni74') }} behavior={componentStatus} /></td> <td class="tg-c3ow" colspan="4">成员</td> <td class="tg-c3ow" colspan="6"><EmployeeField hasClear={true} value={componentIds.employeeField_kt8hni75} onChange={(value) => { this.onChange(value, 'employeeField_kt8hni75') }} behavior={componentStatus} /></td> </tr> </tbody> </table> </div> ); }
为了页面美观,可以先拖动一个容器组件,将按钮组件放入到容器组件中,设置容器样式。
配置远程数据源 >> 按钮组件 >> 动作设置 >> onclik点击事件
变量数据源实现的是点击提交时更改为加载状态,并在提交完成后将按钮和页面内的组件禁用,不允许点击提交第二次。
远程数据源调用「新增表单实例」接口,在 onclik 事件触发后将组件的值更新到 componentIds 变量数据源中,将值作为请求参数给接口,实现将自定义页面组件的值存储到表单的效果。后续为了方便告知自定义页面是否提交完成,定义一个弹出消息框,提交成功或失败都配置了提示。
图3.2-7 将数据存储到依赖表所需数据源
图3.2-8 点击按钮时调用接口将参数传入
下述代码可直接复制编辑 JS 面板内。注意:需要替换 formUuid 和 appType,并在之前完成上述操作。
export function onClick(){ const componentIds = this.state.componentIds console.log('componentIds',componentIds); let loading = this.utils.toast({ type: "loading", title: "提交中..." }); this.setState({ bthLoading: true }); let params = { formUuid: "FORM-XJ866N71G7ET96RS09BNI5ZCKIZM3ZPO6F9TK13", appType: "APP_JKH50FL33A0H8GJBQEHL", formDataJson: JSON.stringify(componentIds) }; this.dataSourceMap.createData.load(params).then(res => { console.log(res); if (res) { loading(); this.utils.toast({ type: "success", title: "提交成功!" }); this.setState({ componentStatus: "DISABLED", bthLoading: false, bthStatus: "DISABLED", }); } }).catch(err => { console.log(err); loading(); this.utils.toast({ type: "error", title: "提交失败!" }); }); }
表格组件 >> 设置远程数据源 >> 绑定表格数据源 >> 添加数据列标题和数据字段
详细配置可以参考:自定义页面表格实现数据管理页功能
图3.3-1 配置表格组件
需要注意的是手写签名组件是一个图片,需要设置列的自定义渲染。
图3.3-2 设置自定义渲染图片
下述代码可直接复制编辑 JS 面板内
export function renderCell(value, index, rowData) { return <span> <img src={value} style={{ display: "block", width: "100px" }} /> </span>; }
提交数据后应该如何实现查看数据也是自定义提交的表格样式呢。
设置表格的操作列 >> 添加名为详情的操作项 >> 点击编辑 >> 绑定回调动作
图3.4.1 绑定操作列回调函数
下述代码可直接复制编辑 JS 面板内,注意:替换链接为自定义提交页面访问链接。
export function onActionClick(rowData) { console.log(rowData) this.utils.router.push("https://www.aliwork.com/APP_JKH50FL33A0H8GJBQEHL/custom/FORM-WO966N71Z6ETTREN3TD4T9QQWDG72EOPEH9TK85", { formInstId: rowData.formInstId }, true, true); }
接口参考文档:根据表单实例 ID 查询表单实例详情
绑定页面加载完成时的 didmount 事件,接收跳转链接携带的参数 formInstId 并作为请求参数传给 getDataById 数据源,加载数据源成功后更改变量内的值。
绑定 didimount 并触发
下述代码可以直接复制到 JS 面板内
export function didMount() { console.log(`「页面 JS」:当前页面地址 ${location.href}`); // console.log(`「页面 JS」:当前页面 id 参数为 ${this.state.urlParams.id}`); // 更多 this 相关 API 请参考:https://www.yuque.com/yida/support/ocmxyv#OCEXd // document.title = window.loginUser.userName + ' | 宜搭'; const { urlParams } = this.state; if (urlParams.formInstId) { let params = { formInstId: urlParams.formInstId }; this.dataSourceMap.getDataById.load(params).then(res => { console.log(res); this.setState({ //用远程数据源返回值赋值给componentIds变量 //给JSX内behavior属性引用的componentStatus变量赋值为只读 //给按钮绑定的状态赋值为禁用,最终让组件重定向渲染 componentIds: res.formData, componentStatus: "READONLY", bthStatus: "DISABLED", }); this.$('JSX_kt9ikv55').forceUpdate(); }); } }
上述操作完成后,可以参考以下内容,介绍自定义页面如何实现表单页面的暂存功能。
准备两个页面,分别是暂存表单和上方已经创建好的自定义提交页面。
暂存表单的作用:用来存储自定义页面暂存的数据。
注意:暂存表单的组件唯一标识要和数据依赖表单相同,所以要采用复制依赖表单页面或者复制组件的方式保证组件唯一标识相同。
暂存表单内新增加两个组件,作用分别是暂存人ID存储操作人工号,暂存时间存储操作时间。
暂存表单页面
新增表单实例:作用是将自定义页面组件内的数据传给依赖/暂存表单中,以便后续调用。
根据条件搜索表单实例详情列表:作用是调用接口查找到当前登陆人在暂存表中的数据,在数据处理中做判断,如果有数据弹窗提醒用户是否需要复用,并将返回数据传给componentIds变量数据源。
删除表单实例:作用是确定将数据复用在页面上后,删除暂存表中的这条数据。
暂存所需远程数据源
在搜索表单实例的远程数据源中做数据处理,运用 JS 面板中定义的 dialog 方法做弹出对话框,参考下述代码。
//远程数据源的数据处理 function didFetch(content) { if (content.totalCount != 0) { //调用 JS 面板的 dialog 方法并传参 this.dialog(content.data[0]); } return content; // 重要,需返回 content }
// JS 面板中的方法 export function dialog(data) { //暂存回写dialog console.log(data); //用于弹出对话框 this.utils.dialog({ method: 'confirm', title: '提示', content: `您于${this.utils.formatter("date", data.formData.dateField_kti1seu4, 'YYYY年MM月DD日hh时mm分ss秒')}暂存了一条数据,是否填充到表单内?`, footerActions: ['cancel', 'ok'], onOk: () => { let params = { formInstId: data.formInstId }; //调用删除表单实例的接口删除这条数据 this.dataSourceMap.delTemporaryData.load(params); this.setState({ componentIds: data.formData }); //给变量数据源赋值后 JSX 渲染 this.$('JSX_kt9ikv55').forceUpdate(); }, onCancel: () => { //当点击取消时将暂存按钮状态设置为禁用,需提前定义名为temporaryBtnStatus的变量数据源 this.setState({ temporaryBtnStatus: "DISABLED" }); }, }); }
temporaryBtnLoading:暂存按钮加载状态
temporaryBtnStatus:暂存按钮状态
控制暂存按钮状态
按钮绑定动作
以下代码可以直接复制在 JS 面板内,注意:需要更改formUuid、appType,和暂存人ID/暂存时间的唯一标识。
export function onClick2() { //暂存按钮绑定动作 const { componentIds } = this.state; //唯一标识需要替换成暂存表单中的暂存人ID和暂存时间唯一标识 componentIds.textField_kti1seu3 = window.loginUser.userId; //暂存人ID componentIds.dateField_kti1seu4 = new Date().getTime(); //暂存时间 let loading = this.utils.toast({ type: "loading", title: "暂存中..." }); this.setState({ temporaryBtnLoading: true }); //需要替换formUuid和appType let params = { formUuid: "FORM-2T866B813EITKW2P59M9KCYDINQB2144S1ITKHK", appType: "APP_JKH50FL33A0H8GJBQEHL", formDataJson: JSON.stringify(componentIds) }; this.dataSourceMap.createData.load(params).then(res => { console.log(res); if (res) { loading(); this.utils.toast({ type: "success", title: "暂存成功!" }); this.setState({ componentStatus: "DISABLED", temporaryBtnLoading: false, bthStatus: "DISABLED", temporaryBtnStatus: "DISABLED" }); } }).catch(err => { console.log(err); loading(); this.utils.toast({ type: "error", title: "暂存失败!" }); }); }
JSX 实现自定义表格的效果演示
提交页面在线体验请移步开发者中心 ? 自定义表格的提交
查看页面在线体验请移步开发者中心 ? 自定义表格查看