page-multipage-form 办理类服务(多流程)模板

解释: 具有导航栏的办理类服务(多流程)模板,通常用来完成复杂多流程表单填写提交工作。本模板包含多个组件,可根据实际需要进行增删,支持代码的二次开发满足个性化诉求。

# 示例

扫码体验
重新加载
请使用百度APP扫码

# 前提条件

# 使用说明

  • 本示例为小程序前端代码,可直接在模拟器和真机预览。
  • 模板中使用的是测试数据,你需要从接口中获取真实的数据。
  • 页面模板功能从开发者工具 v2.25.1-rc 版本开始支持。
  • 该模板使用了 es6 语法,需要开启开发者工具的增强编译,操作步骤参看开启说明;同时也需开启上传代码时样式自动补全。

# 使用步骤

  1. 在小程序根目录执行下方命令,下载页面模板的 npm 包:
npm i @smt-ui-template/page-multipage-form
  1. 将 /node_modules/@smt-ui-template/page-multipage-form 下的 @smt-ui-template-page-multipage-form 文件夹拷贝到当前小程序合适的目录下 (如pages):
.
├── project.swan.json                   
├── app.json                            
├── app.js                              
├── pages
    └── @smt-ui-template-page-multipage-form    // 模板文件
  1. 在小程序根目录的 app.json 中配置模板页面的 path 路径,查看效果,如:
{
    "pages": [
        ...
        "pages/@smt-ui-template-page-multipage-form/index/index",
        "pages/@smt-ui-template-page-multipage-form/result/result",
        ...
    ]
}
  1. 为了方便在开发者工具中查看模板页的效果,可以设置模板页为小程序预览的首页。详情请见自定义编译文档

# 页面内容

模板包含两个页面:多步骤表单页、提交状态页(成功/失败)。

# 多步骤表单页

页面路径:index/index

将整个表单划分为多个步骤,每个步骤收集不同分类的信息,开发者可自定义步骤长度,在每个步骤中提供了单选、多选、输入、上传图片等多种表单类型,可根据实际需求选用,模板还提供了提交状态页面,用于展示表单提交结果。

以下为部分代码示例注解,运行模板请按照上面的【使用步骤】

    <!--  页面加载 -->
    <smt-page-status s-if="isPageLoading || pageResult"
        class="content"
        loading="{{isPageLoading}}"
        icon="{{errorConfig[pageResult].icon}}"
        title="{{errorConfig[pageResult].title}}"
        desc="{{errorConfig[pageResult].desc}}"
        showBtn="{{errorConfig[pageResult].showBtn}}"
        bind:smtreloading="check">
    </smt-page-status>
    <!--  办理类服务(多流程)模板 -->
    <view s-else class="{{isFullScreen ? 'iphonexs' : 'normal'}}">
        <view class="thick-divid">
            <gov-steps
                active="{{active}}"
                line-width="{{2}}"
                steps="{{step}}">
            </gov-steps>
        </view>
        <!--  页面一 -->
        <block s-if="{{active === 1}}">
            <view class="thick-divid">
                <gov-page-title title="标题一" size="middle" hasBorder></gov-page-title>
                <!-- 
                    gov-input 输入框
                    1. ipt-item-type: short/long 标题可是四字或六字
                        在一个表单内,建议使用一致的标题宽度设置
    
                    2.ipt-value= "{{formData.key}}" // 
                    ipt-name="key"
                    ipt-error-info="{{errorInfp.key+Error}}"
                    三项必配置,且key要一致
                    
                    3. 输入框中清除事件 iptKeyClean, input事件 iptKeyInput
    
                -->
                <gov-input
                    type="idcard"
                    ipt-item-type="idcard"
                    ipt-title="身份证号"
                    ipt-value="{{formData.idcard}}"
                    iptErrorInfo="{{errorInfo.idcardError}}"
                    ipt-name="idcard"
                    maxlength="18"
                    ipt-item-width="100%"
                    placeholder-content="请输入"
                    bindiptclean="iptKeyClean"
                    bindkeyinput="iptKeyInput"
                    bindiptblur="iptblursfz">
                </gov-input>
                <gov-input
                    type="number"
                    ipt-item-type="phone"
                    ipt-title="手机号"
                    ipt-value="{{formData.phone}}"
                    ipt-error-info="{{errorInfo.phoneError}}"
                    ipt-name="phone"
                    maxlength="11"
                    ipt-item-width="100%"
                    placeholder-content="请输入"
                    bindiptclean="iptKeyClean"
                    bindkeyinput="iptKeyInput"
                    bindiptblur="iptblursjh">
                </gov-input>
                <gov-picker
                    label="日期"
                    mode=date
                    placeholder="请选择"
                    labelWidth="4em"
                    data-value="date"
                    start="{{startDate}}"
                    end="{{endDate}}"
                    errStatus="{{errorInfo.dateError}}"
                    value="{{formData.date}}"
                    bindchange="handleChange1">
                </gov-picker>
                <gov-picker
                    label="所在位置"
                    mode="location"
                    placeholder="请选择"
                    labelWidth="4em"
                    noborder="{{true}}"
                    errStatus="{{errorInfo.placeError}}"
                    locationName="{{formData.place}}"
                    bindchoosesuccess="choosesuccess"
                    bindchoosefail="choosefail">
                </gov-picker>
            </view>
            <view>
                <gov-page-title title="标题二" size="middle" hasBorder></gov-page-title>
                <gov-input
                    type="text"
                    ipt-item-type="short"
                    ipt-title="输入框"
                    ipt-value="{{formData.iptone}}"
                    ipt-error-info="{{errorInfo.iptoneError}}"
                    ipt-name="iptone"
                    ipt-item-width="100%"
                    placeholder-content="请输入"
                    bindiptclean="iptKeyClean"
                    bindkeyinput="iptKeyInput">
                </gov-input>
                <gov-input
                    type="text"
                    ipt-item-type="short"
                    ipt-title="输入框"
                    ipt-value="{{formData.ipttwo}}"
                    ipt-error-info="{{errorInfo.ipttwoError}}"
                    ipt-notic-info="{{noticInfo.iptNoticInfo}}"
                    ipt-name="ipttwo"
                    ipt-item-width="100%"
                    placeholder-content="请输入"
                    bindiptclean="iptKeyClean"
                    bindkeyinput="iptKeyInput">
                </gov-input>
                <gov-picker 
                    mode="selector"
                    range="{{options.singPicker}}"
                    label="选择框"
                    labelWidth="4em"
                    bindchange="handleChange3"
                    value="{{formData.sltsingle}}"
                    rangeKey="name"
                    errStatus="{{errorInfo.sltsingleError}}"
                    placeholder="请选择">
                </gov-picker>
                <gov-cascade
                    range="{{options.cascader}}"
                    label="选择框"
                    value="{{formData.sltdouble}}"
                    rangeKey="name"
                    labelWidth="4em"
                    tips="{{['请选择', '请选择', '请选择']}}"
                    bindchange="cacadaChange"
                    errStatus= "{{errorInfo.sltdoubleError}}"
                    placeholder="{{['请选择', '请选择', '请选择']}}"/>
            </view>
        </block>
        <!--  页面二 -->
       <block s-if="{{active === 2}}">
            <view class="thick-divid">
                <gov-page-title title="单选标题" size="middle" hasBorder></gov-page-title>
                <view class="radios">
                    <gov-radio-group
                        inline="{{false}}"
                        option-key="name"
                        active-color="#2772fb"
                        options="{{options.radiosValue}}"
                        bindchange="radioChange"
                        value="{{formData.radios}}"> 
                    </gov-radio-group>
                </view>
            </view>
            <view>
                <gov-page-title title="多选标题" size="middle" hasBorder></gov-page-title>
                <view class="checkboxs">
                    <gov-checkbox-group
                        groupStyle="border-bottom: 0.6rpx solid #e6e6e6 !important"
                        inline="{{false}}"
                        option-key="name"
                        activeColor="#2772fb"
                        options="{{options.checkboxsValue}}"
                        bindchange="checkboxChange"
                        gov-checkbox-group="border"
                        value="{{formData.checkbox}}">
                    </gov-checkbox-group>
                    <gov-checkbox
                        bindchange="noHas"
                        activeColor="#2772fb"
                        value="{{formData.nochecked}}"
                        gov-checkbox="border">
                        不含以上情况
                    </gov-checkbox>
                </view>
            </view>
       </block>
       <!--  页面三 -->
       <block s-if="{{active === 3}}">
            <view class="thick-divid">
                <gov-textarea
                    gov-textarea-wrap="textareaWrap"
                    gov-textarea-element="textareaElement"
                    bindinput="iptTextarea"
                    placeholder="请输入"
                    head="长文本输入框标题"
                    value="{{formData.textBox}}"
                    maxlength="100">
                </gov-textarea>          
            </view>
            <view>
                <view class="upload-title">
                    <gov-page-title title="上传照片标题" size="middle" hasBorder></gov-page-title>
                </view>
                <gov-upload
                    count="5"
                    gov-tips="tips"
                    bind:delete="clickDelete"
                    bind:uploadsuccess="uploadsuccess"
                    bind:urlempty="urlempty"
                    bind:previewfail="previewfail"
                    tips="最多支持5张图片,单张体积10M一下"
                    imageList="{{formData.uploadphotos}}"
                    limitSize="10"/>
            </view>
       </block>
       <!--  页面四 -->
       <block s-if="{{active === 4}}">
            <view s-for="informateFour.lists trackBy item" class="thick-divid">
                <gov-page-title title="{{item.bigTitle}}" size="middle" hasBorder></gov-page-title>
                <gov-list-item s-for="items, index in item.msg trackBy index"
                    gov-list-item="listItem"
                    gov-label="label"
                    label="{{items.title}}"
                    labelWidth="4em"
                    content="{{items.sub}}"
                    clickable
                    border="{{index !== item.msg.length-1}}">
                </gov-list-item>
            </view>
            <view  s-for="informateFour.expand trackBy item" class="thick-divid">
                <gov-page-title
                    title="{{item.bigTitle}}"
                    size="middle"
                    gov-title-wrap="titleWrap">
                </gov-page-title>
                <view class="expand-wrap">
                    <gov-text-collapse
                        text="{{item.msg}}"
                        line="5">
                    </gov-text-collapse>
                </view>
            </view>
            <view>
                <gov-page-title title="{{informateFour.photos.bigTitle}}" size="middle" hasBorder></gov-page-title>
                <view class="gov-image-wrap">
                    <gov-image-item s-for="informateFour.photos.msg trackBy item"
                        class="gov-plate-img"
                        image-src="{{item}}"
                        image-width="224.64"
                        image-height="224.64"
                        border-radius="10">
                    </gov-image-item>
                </view>
            </view>
            <view class="wen">
                <gov-prompt>
                    <view slot="title">温馨提示:</view>
                    <view slot="content">此板块为提示区,可用户提醒用户业务填写中的注意事项及要求<view class="prompt-view" bindtap="toView">点击查看</view>
                    </view>
                </gov-prompt>
            </view>
       </block>
       <view class="bottoms"></view>
        <view class="tail">
            <view class="btn">
                <gov-button s-if="{{active !== 1}}"
                    button-size="middle"
                    button-text="上一步"
                    button-color="plain"
                    bindtap="prev">
                </gov-button>
                <gov-button
                    button-size="{{active===1 ? 'large':'middle'}}"
                    button-text="{{active === 4 ? '提交': '下一步'}}"
                    button-color="default"
                    bindtap="next">
                </gov-button>
            </view>
            <view s-if="{{isFullScreen}}" class="{{isFullScreen ? 'iphonex-safe-height': 'normal-height'}}"></view>
        </view>
    </view>
    
    {
        "navigationBarTitleText": "办理类服务(多流程)模板",
        "backgroundColor": "#fff",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTextStyle": "black",
        "usingComponents": {
            "gov-steps": "@smt-ui/component-gov/src/steps",
            "gov-prompt": "@smt-ui/component-gov/src/prompt",
            "gov-picker": "@smt-ui/component-gov/src/picker",
            "gov-upload": "@smt-ui/component-gov/src/upload",
            "gov-input": "@smt-ui/component-gov/src/input",
            "gov-button": "@smt-ui/component-gov/src/button",
            "gov-cascade": "@smt-ui/component-gov/src/cascade",
            "gov-image-item": "@smt-ui/component-gov/src/image-item",
            "gov-textarea": "@smt-ui/component-gov/src/textarea",
            "gov-page-title": "@smt-ui/component-gov/src/page-title",
            "smt-page-status": "@smt-ui/component/src/page-status",
            "gov-list-item": "@smt-ui/component-gov/src/list-item",
            "gov-radio-group": "@smt-ui/component-gov/src/radio-group",
            "gov-checkbox": "@smt-ui/component-gov/src/checkbox",
            "gov-checkbox-group": "@smt-ui/component-gov/src/checkbox-group",
            "gov-text-collapse": "@smt-ui/component-gov/src/text-collapse"
        }
    }
    
    • 获取页面数据
      /**
       * 发送请求
       *
       * @param {Object=} data 请求接口参数
       */
      getDetail(data = {}) {
          //【需替换】:获取内容详情所需要的数据,请修改 url 字段为真实的请求地址,该接口仅做示例
          let params = {
              url: 'https://www.ceshi.com',
              method: 'GET',
              data,
              success: res => {
                  // 接口正常返回处理逻辑
                  if (+res.code === 0) {
                      if (Object.keys(res.data).length) {
                          this.setData({
                              // merge 本地数据和异步数据赋值给 options
                              options: {...this.data.options, ...res.data}
                          }, () => {
                              this.setData({
                                  isPageLoading: false,
                                  pageResult: ''
                              });
                          });
                      }
                      else {
                          // 没有数据
                          this.setData({
                              isPageLoading: false,
                              pageResult: 'noData'
                          });
                      }
                  }
                  else {
                      // 接口异常处理逻辑
                      this.setData({
                          isPageLoading: false,
                          pageResult: 'warning'
                      });
                  }
              },
              fail: err => {
                  // 接口异常处理逻辑
                  this.setData({
                      isPageLoading: false,
                      pageResult: 'warning'
                  });
              }
          };
          swan.request(params);
      }
      
      • 点击下一步按钮触发事件
        /**
         * 点击下一步按钮触发事件
         */
        next() {
            // 输入框,选择框根据错误状态判断 toast 的状态,
            // 多选,单选,长文本,上传照片根据 value 值判断 toast 的状态
            const formData = this.data.formData;
            // datas 用于保存第四步提交时的参数字符串
            let datas = '';
            // this.data.active 表示当前处于第几步
            switch (this.data.active) {
                case 1:
                    this.verifyfirst();
                    break;
                case 2:
                    // 判断第二步单选框是否选择了
                    if (Number(formData.radios) < 0) {
                        this.showToast('请选择单选');
                        return;
                    }
                    // 判断第二步多选框是否选择了
                    if (!formData.checkbox.length && !formData.nochecked) {
                        this.showToast('请选择多选');
                        return;
                    }
                    // 第二步校验通过,设置页面索引为 3
                    this.setData('active', 3);
                    break;
                case 3:
                    // 判断第三步长文本输入框是否有值
                    if (!formData.textBox) {
                        this.showToast('请输入长文本');
                        return;
                    }
                    // 第三步校验通过,设置页面索引为 4
                    this.setData('active', 4);
                    // 核对信息页面的数据
                    this.fiveInfor();
                    break;
                case 4:
                    // 设置参数,参数格式可根据业务接口自定义
                    datas = JSON.stringify(this.parameter());
                    swan.showModal({
                        title: '信息确认信息',
                        content: '请确认填写的信息无误,提交后不支持修改',
                        confirmText: '确认提交',
                        confirmColor: '#108EE9',
                        cancelText: '返回修改',
                        cancelColor: '#999',
                        success(res) {
                            if (res.confirm) {
                                // 此处可自定义业务逻辑
                                swan.redirectTo({
                                    url: `../result/result?result=${datas}`
                                });
                            }
                        }
                    });
                    break;
            }
        }
        
        • 页面一点击下一步时的校验逻辑
          /**
           * 第一步的校验函数,错误飘红,并toast提示相关错误信息
           */
          verifyfirst() {
              // 页面中所有表单输入值的集合
              const formData = this.data.formData;
              // 页面一中 input,选择框的 error 状态设置
              let errorInfo = {
                  // checkIdcard、checkPhone、checkEmpty校验方法的详细说明可看 utils.js
                  idcardError: checkIdcard(formData.idcard),
                  phoneError: checkPhone(formData.phone),
                  dateError: !formData.date,
                  placeError: !formData.place,
                  iptoneError: checkEmpty(formData.iptone, '请输入输入框一'),
                  ipttwoError: checkEmpty(formData.ipttwo, '请输入输入框二'),
                  sltsingleError: formData.sltsingle < 0,
                  sltdoubleError: formData.sltdouble.length !== 3
              };
              this.setData({errorInfo}, () => {
                  this.showCurToast();
              });
          }
          

          # 提交状态页

          页面路径:result/result

          用于展示表单提交结果。

            <smt-page-status s-if="isPageLoading || errorPage"
                class="content"
                loading="{{isPageLoading}}"
                icon="{{errorConfig[errorPage].icon}}"
                title="{{errorConfig[errorPage].title}}"
                desc="{{errorConfig[errorPage].desc}}"
                showBtn="{{errorConfig[errorPage].showBtn}}"
                bind:smtreloading="check">
            </smt-page-status>
            <view s-else class='wrap'>
                <gov-page-result
                    iconName="{{icon.iconName}}"
                    iconColor="{{icon.iconColor}}"
                    gov-main-btn="gov-main-btn" 
                    gov-ext-info-text="gov-ext-info-text" 
                    title="{{pageResult.title}}" 
                    desc="{{pageResult.desc}}"
                    main-btn-text="回到首页" 
                    sub-btn-text="辅助按钮"
                    bind:goback="goBack" 
                    bind:viewdetails="viewDetails"> 
                    <view slot="suppl-cont" class="list" s-if="{{pageResult.list}}">
                        <view s-for="pageResult.list trackBy item" class='every'>
                            <text>{{item.title}}</text>
                            <text>{{item.sub}}</text>
                        </view>
                    </view>
                </gov-page-result>
            </view>
            
            {
                "navigationBarTitleText": "结果页",
                "backgroundColor": "#fff",
                "navigationBarBackgroundColor": "#fff",
                "navigationBarTextStyle": "black",
                "usingComponents": {
                    "ga-button": "@smt-ui/component-gov/src/button",
                    "smt-page-status": "@smt-ui/component/src/page-status",
                    "gov-page-result": "@smt-ui/component-gov/src/page-result"
                }
            }
            
            • 页面初始化
              /**
               * 页面加载时触发
               *
               * @param {Object} options 提交页面传的参数
               * @param {string} options.result 传的数据
               */
              onLoad(options) {
                  this.setData({
                      // 页面需要展示的数据,依赖server端返回
                      pageResult: '',
                      options: JSON.parse(options.result)
                  });
                  let icon;
                  // 根据接口返回的数据或提交页面传入的数据判断需要展示的 icon 类型
                  if (pageResult.data.type !== 'success') {
                      icon = {
                          iconName: 'warning-o',
                          iconColor: '#c40311'
                      };
                      this.setData({icon});
                  }
              }
              
              • 点击 ”返回首页“ 按钮触发事件
                /**
                 * 返回首页
                 */
                goBack() {
                    //【需替换】:请为 url 设置真实的首页路径
                    swan.redirectTo({
                        url: ''
                    });
                }
                
                • 点击 ”辅助按钮“ 按钮触发事件
                  /**
                   * 辅助按钮
                   */
                  viewDetails() {
                      //【需替换】:请为 url 设置真实的跳转页面路径
                      swan.redirectTo({
                          url: ''
                      });
                  }
                  

                  # NPM 依赖

                  名称 版本号
                  @smt-ui/component-gov latest
                  @smt-ui/component latest