Skip to content

首页模板布局(二) ​

本页对应 首页模板布局,共 7 段视频,约 56 分钟。

学习目标 ​

  1. 能够独立创建分包页面并正确配置路由,避免将分包页面误注册到主包。
  2. 能够使用 v-model 获取姓名、身份证号、性别等表单数据,并通过 :model 传给 uni-forms 组件。
  3. 能够通过 switch 的 change 事件读取 event.detail.value,将其转换为后端要求的 0/1,并设置默认选中状态。
  4. 能够为姓名、身份证号、性别配置表单校验规则,并通过 formRef.value.validate() 完成提交前校验。
  5. 能够使用 validateFunction 根据身份证号第 17 位奇偶性校验性别是否一致,并返回对应错误提示。
  6. 能够封装添加患者 API,在保存时提交表单数据,根据返回 code 判断成功并返回患者列表页。

知识点 ​

一、先处理分包页面:不要直接“新建页面”就注册 ​

为什么需要:添加患者页属于分包页面,页面必须注册到分包配置里;如果按 HBuilderX 的“新建页面”并勾选“在 pages.json 中注册”,它容易把页面注册到主包,后面分包结构就乱了。

怎么想:分包目录手动建更灵活,页面名想叫 index 就叫 index,想叫 A 就叫 A。如果仍用“新建页面”,要取消“在 pages.json 中注册”,并注意“同名目录”选项。

怎么做:右键新建文件夹(如 test),在文件夹里新建 .vue 文件作为页面;或者新建页面时取消自动注册。转写中临时建的 test 目录后来删掉了,说明目录名可按项目需要调整。

易错点:勾选自动注册导致主包多出页面;把“新建页面”和“新建文件夹+新建 .vue”混用后找不到注册位置。调试时先看 pages.json 的分包配置,再确认页面路径。

二、先做添加患者页,再连列表入口 ​

为什么需要:列表页要先有患者数据才能看到效果,所以开发顺序应是“先添加患者,再查询列表”。但正常入口确实应跳列表页。

怎么想:为了调试方便,先把入口链接临时改到添加患者页,等功能通了再改回列表页。

怎么做:把入口地址临时改成添加患者页;把表单模板放到 form/index.vue,并新建/引入 SCSS 样式文件。页面本质就是一堆表单项:姓名、身份证号、性别、是否默认就诊人等。

易错点:忘记把入口改回列表页;样式文件没引入导致页面难看;表单项结构不完整。转写中特别提醒:这里没有登录页的验证码、Tab 切换,核心就是“表单验证 + 保存调接口”。

三、获取表单数据:v-model、uni-data-checkbox、switch ​

为什么需要:验证前必须先拿到表单数据。小程序原生表单双向绑定不方便,uni-data-checkbox 封装后支持 v-model,所以性别用它可以方便取值。

怎么想:姓名、身份证号、性别直接绑定到 formData;switch 是原生组件,不支持 v-model,要通过 change 事件拿 e.detail.value。

怎么做(转写中提到的关键片段,字段名以项目为准):

html
<uni-forms ref="formRef" :rules="rules">
  <uni-forms-item name="name">
    <input v-model="formData.name" />
  </uni-forms-item>
  <uni-forms-item name="idCard">
    <input v-model="formData.idCard" />
  </uni-forms-item>
  <uni-forms-item name="gender">
    <uni-data-checkbox v-model="formData.gender" :localdata="genderOptions" />
  </uni-forms-item>
  <switch
    :checked="formData.defaultFlag === 1"
    @change="onSwitchChange"
  />
</uni-forms>
js
function onSwitchChange(e) {
  // 后端要 0/1,不要布尔值
  formData.value.defaultFlag = e.detail.value ? 1 : 0
}

易错点:转写中曾把身份证字段写错,检查后改回 idCard;switch 拿到的是 true/false,必须转成 1/0;uni-data-checkbox 的选项用 localdata,选中颜色可自定义,但不要和原生 radio/checkbox 混用。

四、写验证规则并传给 uni-forms ​

为什么需要:姓名、身份证号、性别要校验;中文姓名和身份证号都有固定规则,默认就诊人可不验证。

怎么想:rules 里每个字段的 name 要和表单项的 name 对应;中文姓名用 Unicode 范围 \u4e00-\u9fa5,限制 2 到 5 个字;身份证号用讲义/工具生成的固定正则,不必背;性别只做必填。

怎么做:

js
const rules = {
  name: {
    rules: [{ required: true }, { pattern: /^[\u4e00-\u9fa5]{2,5}$/, errorMessage: '请输入中文姓名' }]
  },
  idCard: {
    rules: [{ required: true }, { pattern: /身份证号固定正则(以讲义为准)/, errorMessage: '身份证号格式不正确' }]
  },
  gender: {
    rules: [{ required: true }]
  }
}

模板上通过 :rules="rules" 传给 uni-forms。

易错点:表单项 name 和规则字段不一致;转写中曾把 validateFunction 放到 rules 平级,正确应放到 rules 数组里对应对象下;默认就诊人没验证,所以后面 validate() 的返回值里不会包含它。

五、调用 validate 并调整错误提示样式 ​

为什么需要:点保存时先验证;默认错误提示位置不好看,要按 UI 稿调整。

怎么想:用 ref 找到表单组件,调 validate();失败用 try/catch 捕获;错误提示类名是 uni-forms-item__error,可改绝对定位、left: -220rpx、right: 0、top: auto,去掉 transition 小动画。

怎么做:

js
const formRef = ref()

async function onFormSubmit() {
  try {
    await formRef.value.validate()
    // 验证通过
  } catch (e) {
    // 验证失败
  }
}

易错点:ref 名和模板不一致;忘记 await;样式调整要按 UI 稿,不要死记 -220rpx;转写中强调“这里不是永远这样写”。

六、自定义校验:身份证第 17 位判断性别 ​

为什么需要:用户可能身份证是男却选女,要以身份证为准;密码/确认密码也适合这种组合校验。

怎么想:身份证第 17 位奇数为男、偶数为女;在 validateFunction 中取第 17 位,与表单性别比较。

怎么做:

js
validateFunction: function (rule, value, data, callback) {
  const idCard = formData.value.idCard
  const sexBit = Number(idCard.slice(16, 17)) // 第17位从索引16开始
  const idCardGender = sexBit % 2 === 0 ? 0 : 1
  if (idCardGender !== value) {
    callback('与身份证号性别不一致')
  }
  return true
}

易错点:slice 起点写错;validateFunction 层级放错;callback 用来提示错误;测试要用符合规则的身份证号,乱编过不了正则。转写中调试时先 log 参数,确认 value 是当前性别值。

七、封装并调用添加患者接口 ​

为什么需要:验证通过后提交数据,成功返回列表页。

怎么想:患者相关接口单独放 service/patient.js;封装函数要 return 请求结果;页面中 await 验证后提交,判断 code。

怎么做(路径和地址以项目为准):

js
import http from '项目工具目录/http'

export function addPatientAPI(data) {
  return http.post('接口地址(以文档为准)', data)
}
js
const res = await addPatientAPI(formData.value)
if (res.code !== 10000) {
  uni.showToast({ title: res.message })
  return
}
uni.navigateBack()

易错点:封装函数忘记 return;接口参数不要用 validate() 的返回值,因为它只包含被验证字段,默认就诊人不在里面,转写中改为用表单数据;成功判断 code,失败提示 message;navigateBack 依赖入口从列表页跳过来,链接关系要改回列表页。

一、先准备一个可调试的表单页面 ​

为什么需要:添加患者要先有表单页面,才能谈“获取表单数据”。转写稿里先创建分包页面,再把入口链接临时从列表页改到添加页,目的是方便调试。

怎么想:正常流程是列表页 → 添加页,但开发时直接进添加页更快。创建分包页面时不要依赖 HBuilderX 的“新建页面”自动注册,因为它可能把页面注册到主包 pages 下,造成分包配置混乱。转写稿里的“HB there”指 HBuilderX,“点view”指 .vue 文件。

怎么做:右键新建文件夹,再在文件夹里新建 .vue 页面;入口链接先临时指向添加页。静态模板粘贴到 form/index.vue,样式文件改成 scss 并引入。

易错点:新建页面时误勾“在 pages.json 中注册”;页面名与目录名混用;忘记引入样式导致表单排版不对。

二、普通表单项用 v-model 获取数据 ​

为什么需要:姓名、身份证号等数据必须进入 formData,后续验证和提交才有数据源。

怎么想:转写稿明确用 v-model 把输入框和 formData 字段绑定。先定义 formData,再让每个表单项绑定对应字段。

怎么做:

html
<input v-model="formData.name" />
<input v-model="formData.idCard" />
js
const formData = reactive({
  name: '',
  idCard: '',
  gender: '',
  defaultFlag: 0
})

调试时在页面里随便填姓名、身份证号,手动刷新后看数据是否变化。转写稿中曾把 idCard 写成 idcard,测试发现取不到值,改正后才正常。

易错点:字段名拼错;v-model 写成 v-mode;只写输入框不写 formData 初始字段。

三、uni-data-checkbox 为什么能 v-model ​

为什么需要:性别是单选,原生单选/多选在小程序里取数据麻烦,而 uni-data-checkbox 封装后支持 v-model。

怎么想:转写稿解释,小程序没有真正意义上的双向绑定,原生表单取值不方便,所以用 uni-data-checkbox 简化。它的选项通过 localdata 配置,选中颜色也可自定义。

怎么做:

html
<uni-data-checkbox v-model="formData.gender" :localdata="genderOptions" />

测试时切换男/女,观察 formData.gender 是否变为 0/1。

易错点:把 localdata 写成 localData;忘记给 formData.gender 初始值;误以为原生 radio 也能直接 v-model。

四、switch 用 change 事件取布尔值并转 0/1 ​

为什么需要:默认就诊人开关是原生 switch,不支持 v-model,必须通过事件拿值。

怎么想:转写稿先打印事件对象,发现值在 event.detail.value,是 true/false;但接口要求 number 的 0/1,所以用三元转换。

怎么做:

html
<switch :checked="formData.defaultFlag === 1" @change="onDefaultChange" />
js
function onDefaultChange(e) {
  formData.defaultFlag = e.detail.value ? 1 : 0
}

调试时分别打开、关闭开关,看控制台 detail.value 是否为 true/false。

易错点:写成 @change="onDefaultChange()" 导致事件对象丢失;忘记把布尔值转 0/1;checked 前漏写冒号。

五、把数据交给 uni-forms,并注意验证返回值 ​

为什么需要:uni-forms 验证需要 :model 提供数据,:rules 提供规则,validate() 触发验证。

怎么想:转写稿强调三步:取数据 → :model 传给组件 → 定义 rules → 调 validate。验证成功后返回的是“被验证字段”的数据,默认就诊人没写规则,就不会出现在返回值里,所以提交时改用 formData 本身。

怎么做:

html
<uni-forms ref="formRef" :model="formData" :rules="rules">
js
try {
  await formRef.value.validate()
  await addPatientApi(formData)
  uni.navigateBack()
} catch (err) {
  // 处理验证或接口错误
}

易错点:rules 里的 name 与 uni-forms-item 的 name 不一致;validate 拼错;把验证返回值当成完整表单数据。

先判断:switch 为什么不能直接 v-model ​

为什么需要:本页既有 uni-data-checkbox,也有原生 switch。前者是 uni-app 封装组件,支持 v-model,所以性别能直接绑定;switch 是原生组件,转写稿明确说它“根本就不支持 v-model”。如果照搬 v-model,数据不会按预期更新。
怎么想:遇到表单组件先判断它是否支持双向绑定。支持就用 v-model;不支持就监听组件事件,从事件对象里取值。
怎么做:switch 用 @change 监听切换,不要写 v-model。同页的 uni-data-checkbox 可用 v-model 绑定性别,localdata 配选项,选中颜色可按 UI 自定义。
易错点:不要以为“表单组件都能 v-model”。uni-data-checkbox 能,是因为 uni-app 做了封装;原生 switch 不能。拼写也别把 change 写成 chan。

用 change 事件读取 switch 的值 ​

为什么需要:switch 的开关状态不在 v-model 里,必须通过事件拿。转写稿的调试方式是先打印事件对象,再找值。
怎么想:切换开关会触发 change,回调参数是事件对象。关键值在 event.detail.value,它是布尔值:打开为 true,关闭为 false。
怎么做:先写监听并打印,打开、关闭各试一次:

html
<switch @change="onSwitchChange" />
js
onSwitchChange(ev) {
  console.log(ev)
  console.log(ev.detail.value)
}

控制台展开后确认:detail.value 为 true 表示选中,false 表示未选中。
易错点:不要取 ev.value,转写稿明确是 ev.detail.value;也不要只看一次,必须分别测试打开和关闭,否则容易把布尔值方向写反。

布尔值要转成后端需要的 0/1 ​

为什么需要:switch 给的是 true/false,但转写稿里后端接收“默认就诊人”要求 number,并且是 0 和 1。直接传布尔值会导致参数类型不符合接口要求。
怎么想:事件里拿到布尔值后立刻转换,不要等到提交时再补。打开转 1,关闭转 0。
怎么做:

js
onSwitchChange(ev) {
  this.formData.defaultFlag = ev.detail.value ? 1 : 0
}

调试时先打印 ev.detail.value,再打印转换后的 formData.defaultFlag,确认打开为 1、关闭为 0。
易错点:三元表达式方向别写反;字段名统一用 formData,转写稿里的 formDate 是口误/笔误。还要注意后端要数字,不是字符串 "1"。

用 :checked 设置默认开关状态 ​

为什么需要:添加患者时,“默认就诊人”可能需要初始为开或关。只靠用户手动切换不够,需要把表单数据回显到开关上。
怎么想:switch 的选中状态用 :checked 绑定一个布尔表达式。转写稿用 formData.defaultFlag:等于 1 时打开,等于 0 时关闭。
怎么做:

html
<switch
  @change="onSwitchChange"
  :checked="formData.defaultFlag === 1"
/>

测试时把初始值设为 1,开关应默认打开;改成 0,应默认关闭。
易错点::checked 前有冒号,表示绑定表达式;不要写成普通字符串。表达式要返回布尔值,formData.defaultFlag === 1 比直接写数字更稳。

与表单验证、提交整合时的易错点 ​

为什么需要:switch 数据虽然拿到了,但提交时容易漏。转写稿视频7发现:validate() 通过后的返回值只包含“参与验证”的字段,默认就诊人没有写规则,所以不在返回值里。
怎么想:提交数据不要只依赖验证返回值;应使用表单本身的 formData,它包含姓名、身份证号、性别、默认就诊人等完整数据。
怎么做:验证通过后,用 formData 调添加患者接口;switch 的值已在 change 中写入 formData.defaultFlag,提交时自然带上。
易错点:不要因为 validate() 成功就以为所有字段都在返回值里;未参与 rules 的 switch 字段要额外确认。调试时先打印 formData,确认 defaultFlag 是 0/1 再提交。

代码示例 ​

1. 添加患者表单页(pages/patient/form/index.vue)——模板 + 数据获取 + 验证规则 + 提交

vue
<template>
  <view class="form-page">
    <uni-forms ref="formRef" :model="formData" :rules="rules" label-width="90px">
      <uni-forms-item label="患者姓名" name="name">
        <input v-model="formData.name" placeholder="请输入患者姓名" />
      </uni-forms-item>

      <uni-forms-item label="身份证号" name="idCard">
        <input v-model="formData.idCard" placeholder="请输入身份证号" />
      </uni-forms-item>

      <uni-forms-item label="患者性别" name="gender">
        <uni-data-checkbox
          v-model="formData.gender"
          :localdata="genderOptions"
          selectedColor="#27ba9b"
        />
      </uni-forms-item>

      <uni-forms-item label="默认就诊人">
        <switch
          :checked="formData.defaultFlag === 1"
          @change="onSwitchChange"
        />
      </uni-forms-item>
    </uni-forms>

    <button type="primary" @click="onFormSubmit">保存</button>
  </view>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { addPatientAPI } from '@/services/patient'

// 表单组件实例,用来调 validate 方法
const formRef = ref()

// 表单数据:name / idCard / gender / defaultFlag
const formData = reactive({
  name: '',
  idCard: '',
  gender: 1,
  defaultFlag: 0
})

// uni-data-checkbox 的选项数据(localdata)
const genderOptions = [
  { text: '男', value: 1 },
  { text: '女', value: 0 }
]

// switch 没有 v-model,只能监听 change,从事件对象里取值
const onSwitchChange = (e) => {
  // 接口要求 0/1 的数字,而不是 true/false
  formData.defaultFlag = e.detail.value ? 1 : 0
}

// 自定义校验:身份证第 17 位(索引 16)奇数为男、偶数为女
const validateGender = (rule, value, data, callback) => {
  const genderByIdCard = Number(data.idCard.slice(16, 17)) % 2 === 0 ? 0 : 1
  if (genderByIdCard !== value) {
    callback('与身份证号中的性别不一致')
  } else {
    callback()
  }
}

const rules = {
  name: {
    rules: [
      { required: true, errorMessage: '请输入患者姓名' },
      { pattern: /^[\u4e00-\u9fa5]{2,5}$/, errorMessage: '姓名须为2-5位中文' }
    ]
  },
  idCard: {
    rules: [
      { required: true, errorMessage: '请输入身份证号' },
      {
        pattern: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/,
        errorMessage: '身份证号格式不正确'
      }
    ]
  },
  gender: {
    rules: [
      { required: true, errorMessage: '请选择性别' },
      { validateFunction: validateGender }
    ]
  }
  // defaultFlag 不是必填项,不写规则
}

const onFormSubmit = async () => {
  try {
    // 校验通过才会往下走
    await formRef.value.validate()

    // 注意:用 formData 本身,不要用 validate() 的返回值
    const res = await addPatientAPI(formData)

    if (res.code !== 10000) {
      uni.showToast({ title: res.message, icon: 'none' })
      return
    }

    // 添加成功,返回上一页(患者列表页)
    uni.navigateBack()
  } catch (err) {
    console.log('表单校验失败', err)
  }
}
</script>

要点:

  • 表单验证三件套::model="formData" 把数据交给 uni-forms;:rules="rules" 定义规则;formRef.value.validate() 触发校验,缺一不可。
  • uni-data-checkbox 支持 v-model,所以性别直接 v-model="formData.gender";原生 switch 不支持 v-model,必须 @change 拿 e.detail.value。
  • switch 的 e.detail.value 是布尔值,而接口要 0/1 数字,所以用三元转一次;回显用 :checked="formData.defaultFlag === 1"。
  • 每个 uni-forms-item 的 name 必须和 rules 里的键、formData 里的字段名三者一致,否则规则不生效(最常见错误)。
  • validateFunction 要和普通规则一样放进对应字段的 rules 数组里,不能平级写到 rules 对象下;函数必须调用 callback()(通过)或 callback('提示文字')(不通过)。
  • 提交时传 formData 而不是 validate() 的返回值:validate() 只会返回“被验证过的字段”,defaultFlag 没写规则,就不会出现在返回值里,会漏参。
  • 姓名正则 [\u4e00-\u9fa5] 是 Unicode 汉字编码范围,身份证第 17 位用 slice(16, 17) 取(索引从 0 开始)。

2. 患者相关接口封装(services/patient.js)

js
import { http } from '@/utils/http'

// 添加患者:POST 提交四个参数,成功返回新患者 id
export const addPatientAPI = (data) => {
  return http({
    url: '/patient/add',
    method: 'POST',
    data
  })
}

要点:

  • 按业务分文件:用户相关放 user.js,患者相关新建 patient.js,别全塞一个文件。
  • 方法名以 API 结尾,调用处一眼能看出是在发请求。
  • 一定要 return,否则页面里 await addPatientAPI(...) 拿不到结果。
  • url 以接口文档为准,method 必须是 POST,参数通过 data 传。

3. 错误提示样式调整(pages/patient/form/index.scss)

scss
.form-page {
  padding: 30rpx;

  // 覆盖 uni-forms 内置的错误提示盒子
  ::v-deep .uni-forms-item__error {
    position: absolute;
    left: -220rpx; // 左边界对齐到整行最左侧
    right: 0;      // 右边也贴边,相当于占满整行
    top: auto;
    color: #f56c6c;
    font-size: 24rpx;
    // transition: all 0.3s;  // 注释掉即去掉淡入动画
  }
}

要点:

  • 类名 .uni-forms-item__error 是组件内部类,需要 ::v-deep 才能穿透 scoped 样式生效。
  • left: -220rpx 是量出来的偏移量,用来把提示文字从“标签右侧”拉到整行最左边,具体数值随 UI 稿调整。
  • 去掉过渡动画就把 transition 那行注释掉,不是删掉别的东西。
  • 这段样式是按设计稿改的,换项目要按自己的 UI 结果重新量,不是固定写法。

常见错误 ​

  1. 现象:新建分包页面后被注册到主包 pages.json。→ 原因:使用 HBuilderX“新建页面”时勾选了“在配置中注册”,工具按主包页面处理。→ 修法:分包页面改为右键新建文件夹,再手动新建 .vue 页面文件,或取消自动注册后手动配置到对应分包。
  2. 现象:表单字段能输入但取不到值,或提交数据字段名不对。→ 原因:v-model 绑定字段拼写与数据对象不一致,如 ID card、gender、defaultFlag 等未对齐。→ 修法:逐项核对 formData 字段名,并用控制台即时验证每个字段。
  3. 现象:switch 获取到 true/false,接口却要求 0/1。→ 原因:直接使用原生 switch 的 change 事件值,未按后端类型转换。→ 修法:监听 change,从 e.detail.value 取值后转换为数字 1/0,并同步到表单数据。
  4. 现象:验证规则不生效或提示字段错位。→ 原因:rules 中字段名未与表单项 name 对应,或把自定义校验写到了 rules 数组外。→ 修法:确保每个待校验项设置正确 name,并把自定义校验对象放回 rules 数组内。
  5. 现象:自定义校验函数报错或不提示错误。→ 原因:validateFunction 未 return 校验结果,或失败时未调用 callback 传入提示语。→ 修法:通过返回布尔值控制通过/失败,失败时用 callback('提示信息') 明确提示。
  6. 现象:提交时表单数据缺少“默认就诊人”。→ 原因:直接使用 validate() 的返回值,而该返回值只包含参与校验的字段。→ 修法:提交时使用表单组件当前完整数据或原 formData,不要误以为验证返回值等于完整表单数据。
  7. 现象:接口封装后页面调用拿不到返回值。→ 原因:封装的 API 方法内部发起请求但未 return。→ 修法:在 API 方法中 return http(...),页面侧再 await 接收结果并判断 code。

练习 ​

  1. 在一个分包中手动创建 form/index.vue 页面,并说明为什么不使用“新建页面”的自动注册;完成后检查 pages.json 中该页面是否只出现在分包配置内。
  2. 完成添加患者表单四个核心数据的获取:姓名、身份证号、性别、默认就诊人;要求控制台分别验证 switch 切换前后得到 0/1,而不是 true/false。
  3. 为姓名、身份证号、性别配置验证规则,并补一个自定义校验:身份证号第 17 位表示的性别必须与所选性别一致;分别用男、女测试数据验证错误提示。
  4. 封装“添加患者”API,并在保存按钮中完成:表单验证 → 提交完整表单数据 → 判断 code → 成功后返回上一页;要求接口方法必须 return 请求结果。
  5. 排查一个模拟问题:提交时数据缺少 defaultFlag,请定位是验证返回值导致还是 switch 数据未同步导致,并写出修复步骤。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1优医咨询-添加患者模板05:25
2优医咨询-获取表单数据05:07
3优医咨询-switch数据获取08:55
4优医咨询-表单验证规则07:28
5优医咨询-调用验证方法06:37
6优医咨询-验证身份证号中的性别11:10
7优医咨询-添加患者11:56

小结 ​

  1. 分包页面创建方式要明确:自动新建页面容易误注册到主包,手动建文件夹和页面更可控。
  2. 添加患者功能的主线是:先做添加页,再联调列表;调试阶段可临时改跳转入口。
  3. 表单验证仍按“数据绑定 → 规则定义 → 调用验证”推进,但字段 name 对齐是前提。
  4. uni-data-checkbox 的价值在于配合 v-model 简化选择数据获取;原生 switch 则需监听事件并手动同步。
  5. 自定义校验适合处理组合关系,如身份证性别与所选性别一致性;规则位置和回调写法必须正确。
  6. 提交数据应使用完整表单数据,不能把 validate() 返回值直接等同于全部业务字段。
  7. 接口封装要返回请求结果,页面侧要判断业务 code,成功后按产品流程返回列表页。
  8. 错误提示样式需按 UI 稿调整;理解类名覆盖、定位和过渡效果的作用即可,不必死记固定样式。