diff --git a/docs/dev_readme.md b/docs/dev_readme.md
index 20f28d8..46b8d35 100644
--- a/docs/dev_readme.md
+++ b/docs/dev_readme.md
@@ -20,6 +20,27 @@
两种方法表单设计器支持内容一致,也都支持流程,差别只是UI方面。建议在设计业务模块优先使用代码模版。
+### 表单的封装层次是什么
+```
+formCreatePage/approveFlowPage/createFlow(二开封装页面,提供标题栏和路由功能)
+↓
+FormInformation(最外层表单封装,用于区分是低开模式还是源码模式)
+↓
+Form.vue(业务表单,生成的代码,低开没有这层)
+↓
+SimpleForm/SimpleFormSetup(主体表单封装)
+↓
+SimpleFormItem(表单字段)
+↓
+表单组件 / SubFormV2(嵌套明细表)
+```
+### 表单提供了什么封装函数
+在生成的Form.vue中,可以通过systemFormRef.value调用对外提供的函数,这些函数在SimpleForm.vue里可以找到,可以参考formApi或者defineExpose提供的函数,有用的函数如:
+
+- setFieldsValue 设定字段的值
+- getFieldsValue 获取表单的值,也就是formModel的非响应式版本
+- validateFields 手动触发校验
+
### 如何定义onChange/blur事件
所有的事件都在字段的events中,如change、blur,没有on,主表单的函数定义为
diff --git a/docs/表单二开/4_表单tab页拆分+改为进度条样式.md b/docs/表单二开/4_表单tab页拆分+改为进度条样式.md
index 72e109a..a4f930a 100644
--- a/docs/表单二开/4_表单tab页拆分+改为进度条样式.md
+++ b/docs/表单二开/4_表单tab页拆分+改为进度条样式.md
@@ -1 +1,208 @@
# 二开实例:Tab页拆分+样式调整+校验
+
+首先,我们新建一个具有若干文本框的例子,这里只讲思路,因此不设计其他字段,也不做除了必填的其他校验,我们的要求是,Tab页拆分的内容可以随便切换填写,但是**步骤表示的必须先写当前步骤才能填写后续内容**。
+
+代码因为篇幅限制,去掉了和思路无关的部分。
+
+```vue
+
+
+
+
+
+
+```
+可以看出,在进行二开拆分后,使用v-if、v-show配合响应式变量定义,可以轻松拆分选项卡和步骤条。这里特别注意的是,子类需要继承父类的expose方法,而正常情况下该需求无法实现,这里可以实现的原因是父类的formApi实际上就是expose的全部内容,因此我们在对外暴露的时候,只需要合并formApi就可以,对于其他组件,该方法不成立。
+
+除了父类的内容外,我们还对外提供了切换选项卡和步骤的方法,以便校验错误的时候跳转到对应选项卡,方便修改。
+
+接下来要手动修改原有的验证方法,打开components/Form.vue文件,也就是代码自动生成的表单。
+```javascript
+// 校验form 通过返回表单数据
+async function validate() {
+ let values = [];
+ try {
+ /* 这里就是我们的方法,这个返回值很有迷惑性,values在校验失败的时候是false,成功时候为key-value的对象,不是数组 */
+ values = await /*systemFormRef.value?.validate()*/ customValidate();
+ //添加隐藏组件
+ // 无关代码省略
+ } finally {
+ }
+ return values;
+}
+```
+然后手动实现校验过程:
+```javascript
+import { useMessage } from '/@/hooks/web/useMessage';
+const { createMessage } = useMessage();
+
+function validateField(schema, formValues) {
+ // 这里只考虑了必填校验 如果需要其他校验自己完成
+ if (!schema?.componentProps?.required) {
+ return true;
+ }
+ return formValues[schema.field];
+}
+
+async function customValidate() {
+ const schemas = data.formDataProps.schemas;
+ // 组件在选项卡的第几页,实际上每个选项卡要校验的不止一个字段
+ const pageMapping = {
+ wenBenKuang17845: 0,
+ wenBenKuang46888: 1,
+ wenBenKuang73214: 2
+ };
+ // 组件在步骤的第几页
+ const stepMapping = {
+ buZhou119202: 0,
+ buZhou212978: 1,
+ buZhou316637: 2
+ };
+ const stepFlag = [1, 1, 1];
+ const formValues = systemFormRef.value.getFieldsValue(); // 这个函数可以取到formModel
+ let pageField = null;
+ // 这种遍历只针对主表有效,如果用了子表还要对子表校验
+ for (let i = 0; i < schemas.length; i++) {
+ let schema = schemas[i];
+ if (validateField(schema, formValues)) {
+ continue;
+ }
+ const field = schema.field;
+ // 记下来第一个未通过的字段,后面都不需要校验了,因为要跳转过去
+ if (pageMapping[field] !== undefined && pageField === null) {
+ pageField = pageMapping[field];
+ break;
+ }
+ // 记下来哪些步骤页面没填完
+ if (stepMapping[field] !== undefined) {
+ stepFlag[stepMapping[field]] = 0;
+ }
+ }
+ if (pageField !== null) {
+ systemFormRef.value.onClickTab(pageField);
+ // 手动触发一次校验函数,让红框显示出来
+ systemFormRef.value.validate();
+ return Promise.reject(false);
+ }
+ const strStepFlag = stepFlag.join('');
+ // 拼接后的步骤标志1表示填完,0表示没填完,如果出现01的序列,如101,表示步骤1填了,步骤2没填,步骤3填了
+ // 按照我们假定的场景,只有1填完才能填2
+ const valResult = strStepFlag.indexOf('01');
+ if (valResult > -1) {
+ // 假设序列为101,那返回值为1,也就是步骤2没填
+ createMessage.warn(`步骤${valResult + 1}完成后才能填写后面内容`);
+ systemFormRef.value.onClickTab(2); // 我们知道哪页有步骤条,所以可以写死
+ systemFormRef.value.onClickStep(valResult);
+ return Promise.reject(false);
+ }
+ return formValues;
+}
+```