cloud-web-corejs 1.0.54-dev.708 → 1.0.54-dev.709
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -90,6 +90,12 @@
|
|
|
90
90
|
<th>{{ $t2("文件编码", "components.fileLibrary.fileSn") }}</th>
|
|
91
91
|
<td colspan="3">{{ attachmentDTO.fileSn }}</td>
|
|
92
92
|
</tr>
|
|
93
|
+
<tr>
|
|
94
|
+
<th>{{ $t1("作者") }}</th>
|
|
95
|
+
<td>{{ attachmentDTO.fileAuthor }}</td>
|
|
96
|
+
<th>{{ $t1("修订人") }}</th>
|
|
97
|
+
<td>{{ attachmentDTO.fileReviser }}</td>
|
|
98
|
+
</tr>
|
|
93
99
|
<tr>
|
|
94
100
|
<th>{{ $t2("创建人", "system.label.createBy") }}</th>
|
|
95
101
|
<td>{{ attachmentDTO._createBy }}</td>
|
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
# xform 表单「新增页签模式」实现方案
|
|
2
|
+
|
|
3
|
+
> 面向 `src/components/xform` 表单/页面,增加一种可配置的页签交互模式:
|
|
4
|
+
> 去掉固定「常规」页签 → 新增打开独立页签(标题"新增")→ 保存后本页变编辑态(标题变单号)→ 提交(启动流程)后可配置「关闭页签回列表刷新」或「刷新本页」。
|
|
5
|
+
>
|
|
6
|
+
> 本文档只做方案设计,不含落地代码改动。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 一、需求理解与术语对齐
|
|
11
|
+
|
|
12
|
+
### 1.1 需求逐条拆解
|
|
13
|
+
|
|
14
|
+
| # | 需求描述 | 语义明确化 |
|
|
15
|
+
|---|---------|-----------|
|
|
16
|
+
| 1 | **去掉常规** | 启用本模式后,不再使用 `list.vue` 中固定 `name="first"`、label 为「常规」的 el-tab-pane 承载新增/编辑;列表页签保留,新增与编辑都走**动态可关闭页签** |
|
|
17
|
+
| 2 | **新增打开页签(页签名新增)** | 点击「新增」按钮 → 新开一个标题为「新增」的可关闭页签,渲染新增表单(`addFormCode`) |
|
|
18
|
+
| 3 | **保存后刷新本页面变成编辑界面(页签名为单号)** | 暂存/保存成功后:①当前页签标题从「新增」变为返回的单号(`res.objx`);②`dataId` 更新为单号;③`formCode` 切到 `editFormCode`;④重新加载表单进入编辑态。**不新开页签、不切到列表** |
|
|
19
|
+
| 4 | **提交(启动流程)后支持配置** | 在表单配置里新增枚举项 `submitBehavior`,取值二选一:<br>• `closeToList`:关闭当前页签 → 切到列表页签 → 刷新列表<br>• `refreshCurrent`:刷新当前页签(保持编辑态) |
|
|
20
|
+
|
|
21
|
+
### 1.2 关键术语
|
|
22
|
+
|
|
23
|
+
- **常规页签**:`src/views/user/form/view/list.vue` 第 10 行 `<el-tab-pane :label="$t2('常规')" name="first">`,是固定的新增/编辑容器。
|
|
24
|
+
- **列表页签**:同文件 label 为「列表」/`customListTabLabel`,`name="second"`。
|
|
25
|
+
- **动态编辑页签**:`#editTab` 插槽渲染,`closable=true`,标题取 `tab.data[tab.tabLabelField]`。已有 `multiTabEnabled` 仅对**编辑**(有 dataId)生效。
|
|
26
|
+
- **单号**:保存接口返回的 `res.objx`,即新增记录的主键/dataId。
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 二、现状分析
|
|
31
|
+
|
|
32
|
+
### 2.1 两套页签系统(必须先厘清)
|
|
33
|
+
|
|
34
|
+
| 系统 | 位置 | 作用 | 标题来源 | 本方案是否涉及 |
|
|
35
|
+
|------|------|------|----------|---------------|
|
|
36
|
+
| **A. 路由级 tagsView** | `src/layout/components/TagsView/index.vue` + `store/modules/tagsView.js`(混淆) | 顶部导航栏,每个路由一个页签 | `route.meta.title` | **不涉及**(本需求是页面内交互,不动路由页签) |
|
|
37
|
+
| **B. 页面内 x-tabs** | `src/components/vb-tabs/x-tabs.vue` + `src/views/user/form/view/list.vue` | 单页面内 列表/常规/动态编辑 子页签 | `tab.data[tab.tabLabelField]` | **本方案核心改造对象** |
|
|
38
|
+
|
|
39
|
+
> ⚠️ `src/components/xform/XFormTabContainer/IMPLEMENTATION_PLAN.md` 是一份 **Vue3 风格**(ref/setup/defineComponent)的草案,与本项目 **Vue 2 Options API** 不匹配,且采用「新建独立容器组件」的思路,与现有 `list.vue` + `x-tabs` 体系割裂。**本方案不沿用该草案**,而是基于现有 `x-tabs` 最小化扩展。
|
|
40
|
+
|
|
41
|
+
### 2.2 相关文件清单
|
|
42
|
+
|
|
43
|
+
| 文件 | 作用 | 本方案是否改动 |
|
|
44
|
+
|------|------|---------------|
|
|
45
|
+
| `src/components/xform/form-designer/designer.js` (L51-108) | `formConfig` 默认值定义 | ✅ 新增 3 个默认字段 |
|
|
46
|
+
| `src/components/xform/form-designer/setting-panel/form-setting.vue` | 表单级配置 UI(`el-collapse` 分组) | ✅ 新增/扩展配置分组 |
|
|
47
|
+
| `src/views/user/form/view/list.vue` | xform 动态表单视图页(列表+页签宿主) | ✅ 改造 `openEditDialog` 新增分支、`reload` 回调 |
|
|
48
|
+
| `src/components/xform/mixins/defaultHandle.js` (L113-199) | `saveDefaultHandle` / `saveAndSubmitWfHandle` | ✅ 保存后通知父组件更新页签标题;提交后按配置分支 |
|
|
49
|
+
| `src/components/xform/form-render/indexMixin.js` (L2774-2791) | `switchToListTab` / `getListPageRef` | ⛔ 不改,直接复用 |
|
|
50
|
+
| `src/components/wf/wf.js` (L1817-1852) | `startSubmitHanlde` 流程启动回调 | ⛔ 不改,通过 `onStartSuccess` 注入行为 |
|
|
51
|
+
| `src/components/vb-tabs/x-tabs.vue` | 页面内页签组件 | ⛔ 不改(通过传入构造好的 row + tabParam 复用现有 API) |
|
|
52
|
+
| `src/layout/components/TagsView/index.vue` | 路由级页签 | ⛔ 不涉及 |
|
|
53
|
+
|
|
54
|
+
### 2.3 现有 `multiTabEnabled` 的局限
|
|
55
|
+
|
|
56
|
+
`list.vue:302`:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
if (multiTabEnabled && dataId) { // ← 必须有 dataId 才开页签
|
|
60
|
+
this.$refs.xTabs.openEditTab(row, param, {
|
|
61
|
+
tabParam: { formCode, tabLabelField, tabName: formCode + dataId },
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
this.formCode1 = formCode;
|
|
65
|
+
this.activeName = option.activeName || "first"; // ← 新增(dataId=null)走"常规"页签
|
|
66
|
+
this.$openEditView("showEdit");
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**新增(`dataId=null`)永远走 else 分支 → 进「常规」页签**。本方案要补齐的正是这个缺口。
|
|
71
|
+
|
|
72
|
+
### 2.4 保存与提交的现有链路
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
saveDefaultHandle (defaultHandle.js:153)
|
|
76
|
+
└─ success: formRef.reloadForm({ updateParam: { dataId: res.objx, formCode: editFormCode } })
|
|
77
|
+
└─ reloadForm (indexMixin.js:2792) → this.$emit("reload", this, param)
|
|
78
|
+
└─ list.vue 的 reload(...) 接收 ← 【本方案在此更新页签标题】
|
|
79
|
+
|
|
80
|
+
saveAndSubmitWfHandle (defaultHandle.js:113)
|
|
81
|
+
└─ success: openStartWfDialog(formRef, { objId: res.objx, ... })
|
|
82
|
+
└─ wf.js:1829 startSubmitHanlde
|
|
83
|
+
└─ 默认 that.$baseReload() 或 option.onStartSuccess() ← 【本方案在此按配置分支】
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`switchToListTab({ handleType: 'reload' })`(indexMixin.js:2774)已是现成方法:切到 `name="second"` 列表页签并刷新列表。
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 三、设计决策
|
|
91
|
+
|
|
92
|
+
### 3.1 核心原则
|
|
93
|
+
|
|
94
|
+
1. **基于现有 `x-tabs` 扩展,不新建容器组件**。`IMPLEMENTATION_PLAN.md` 的 Vue3 容器方案与本项目技术栈不符,弃用。
|
|
95
|
+
2. **最小侵入 + 向后兼容**。新增配置项默认关闭,旧表单行为完全不变。
|
|
96
|
+
3. **复用现有 API**:`xTabs.openEditTab`、`switchToListTab`、`reloadForm`、`onStartSuccess` 钩子。
|
|
97
|
+
4. **页签标题响应式更新**:x-tabs 标题绑定 `tab.data[tabLabelField]`,保存后更新该字段即可自动变标题,**无需改 x-tabs**。
|
|
98
|
+
|
|
99
|
+
### 3.2 配置项设计
|
|
100
|
+
|
|
101
|
+
在 `formConfig` 中新增 3 个字段(`designer.js` 默认值 + `form-setting.vue` UI):
|
|
102
|
+
|
|
103
|
+
| 字段名 | 类型 | 默认值 | 含义 | 依赖 |
|
|
104
|
+
|--------|------|--------|------|------|
|
|
105
|
+
| `addTabEnabled` | Boolean | `false` | **新增是否打开独立页签**(本模式总开关)。开启后:新增不再走「常规」页签,而是开一个标题「新增」的可关闭页签 | 无 |
|
|
106
|
+
| `addTabLabel` | String | `"新增"` | 新增页签的初始标题文本(支持 i18n key) | `addTabEnabled` |
|
|
107
|
+
| `submitBehavior` | String | `"closeToList"` | 提交(启动流程)成功后的行为枚举:<br>• `closeToList`:关闭当前页签 → 切列表 → 刷新列表<br>• `refreshCurrent`:刷新当前页签(保持编辑态) | `addTabEnabled` 或 `wfEnabled` |
|
|
108
|
+
|
|
109
|
+
> 💡 **与现有 `multiTabEnabled` 的关系**:
|
|
110
|
+
> - `multiTabEnabled` 控制编辑页签(有 dataId)是否多开,保持原语义不变。
|
|
111
|
+
> - `addTabEnabled` 控制新增页签是否多开,**独立开关**,互不干扰。
|
|
112
|
+
> - 二者可同时开启(推荐:完整的列表+多页签新增/编辑体验),也可单独开启。
|
|
113
|
+
> - 当 `addTabEnabled=true` 时,**「常规」页签(name="first")在新增加页签场景下不再被激活**;但为兼容其它走 `activeName="first"` 的逻辑(如复制编辑 `openCopyEditTab`),保留该 pane 不删除,仅在 `openEditDialog` 新增分支里改走 `xTabs.openEditTab`。
|
|
114
|
+
|
|
115
|
+
### 3.3 UI 配置位置
|
|
116
|
+
|
|
117
|
+
在 `form-setting.vue` 的 `el-collapse` 中**新增一个分组**(建议 name="9",标题「页签交互模式」),紧挨「列表标签页信息」(name=4) 之后:
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<el-collapse-item name="9" title="页签交互模式">
|
|
121
|
+
<el-form-item :label="i18nt('新增打开页签')">
|
|
122
|
+
<el-switch v-model="formConfig.addTabEnabled"></el-switch>
|
|
123
|
+
<span class="hint">开启后新增将打开独立可关闭页签,不再使用"常规"页签</span>
|
|
124
|
+
</el-form-item>
|
|
125
|
+
<el-form-item :label="i18nt('新增页签标题')">
|
|
126
|
+
<el-input type="text" v-model="formConfig.addTabLabel"
|
|
127
|
+
placeholder="默认'新增'"></el-input>
|
|
128
|
+
</el-form-item>
|
|
129
|
+
<el-form-item :label="i18nt('提交后行为')">
|
|
130
|
+
<el-radio-group v-model="formConfig.submitBehavior">
|
|
131
|
+
<el-radio label="closeToList">关闭页签并回列表刷新</el-radio>
|
|
132
|
+
<el-radio label="refreshCurrent">刷新当前页签</el-radio>
|
|
133
|
+
</el-radio-group>
|
|
134
|
+
<span class="hint">仅在启用流程(wfEnabled)时生效</span>
|
|
135
|
+
</el-form-item>
|
|
136
|
+
</el-collapse-item>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 四、核心改造点详解
|
|
142
|
+
|
|
143
|
+
### 4.1 改造点 1:`designer.js` 新增默认字段
|
|
144
|
+
|
|
145
|
+
**文件**:`src/components/xform/form-designer/designer.js`(L51-108 的 formConfig 对象)
|
|
146
|
+
|
|
147
|
+
**改动**:在 `multiTabEnabled` 附近新增:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
formConfig: {
|
|
151
|
+
// ... 现有字段
|
|
152
|
+
multiTabEnabled: false,
|
|
153
|
+
multiTabLabelField: null,
|
|
154
|
+
// ★ 新增
|
|
155
|
+
addTabEnabled: false, // 新增打开独立页签
|
|
156
|
+
addTabLabel: "新增", // 新增页签初始标题
|
|
157
|
+
submitBehavior: "closeToList", // 提交后行为: closeToList | refreshCurrent
|
|
158
|
+
// ...
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 4.2 改造点 2:`list.vue` 的 `openEditDialog` 新增分支
|
|
163
|
+
|
|
164
|
+
**文件**:`src/views/user/form/view/list.vue`(L269-319)
|
|
165
|
+
|
|
166
|
+
**现状**:`if (multiTabEnabled && dataId)` 只对编辑开页签,新增走 else。
|
|
167
|
+
|
|
168
|
+
**改造**:在新增(`!dataId`)场景下,根据 `addTabEnabled` 决定是否开页签。
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
openEditDialog(row, param, option) {
|
|
172
|
+
// ... 现有 otherTab / H5 分支不变
|
|
173
|
+
|
|
174
|
+
let formConfig = this.formJson.formConfig;
|
|
175
|
+
let tabLabelField = option?.multiTabLabelField || formConfig.multiTabLabelField;
|
|
176
|
+
let multiTabEnabled = /* 现有计算逻辑不变 */;
|
|
177
|
+
|
|
178
|
+
let dataId = row && row.id ? row.id : null;
|
|
179
|
+
this.dataId = dataId;
|
|
180
|
+
let formCode = !dataId
|
|
181
|
+
? (option?.formCode || this.addFormCode)
|
|
182
|
+
: (option?.formCode || this.formCode2);
|
|
183
|
+
|
|
184
|
+
// ★ 新增:addTabEnabled 分支
|
|
185
|
+
let addTabEnabled = formConfig.addTabEnabled && !dataId && tabLabelField;
|
|
186
|
+
|
|
187
|
+
if (multiTabEnabled && dataId) {
|
|
188
|
+
// —— 现有编辑页签分支,保持不变 ——
|
|
189
|
+
this.$refs.xTabs.openEditTab(row, param, {
|
|
190
|
+
tabParam: { formCode, tabLabelField, tabName: formCode + dataId },
|
|
191
|
+
});
|
|
192
|
+
} else if (addTabEnabled) {
|
|
193
|
+
// ★ 新增页签分支
|
|
194
|
+
// 构造一个"虚拟 row",让 x-tabs 标题先显示"新增"
|
|
195
|
+
// 保存成功后在 reload 回调里把 tabLabelField 字段更新为真实单号
|
|
196
|
+
let addLabel = formConfig.addTabLabel || "新增";
|
|
197
|
+
let virtualRow = { ...row };
|
|
198
|
+
if (tabLabelField) virtualRow[tabLabelField] = addLabel;
|
|
199
|
+
let tabName = "add_" + Date.now(); // 唯一,避免新增页签互相覆盖
|
|
200
|
+
this.$refs.xTabs.openEditTab(virtualRow, param, {
|
|
201
|
+
tabParam: { formCode, tabLabelField, tabName },
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
// —— 现有"常规"页签分支,保持不变(向后兼容) ——
|
|
205
|
+
this.formCode1 = formCode;
|
|
206
|
+
this.activeName = option.activeName || "first";
|
|
207
|
+
this.showEdit = false;
|
|
208
|
+
this.showEditDialog = true;
|
|
209
|
+
this.param = param;
|
|
210
|
+
this.formData = null;
|
|
211
|
+
this.$openEditView("showEdit");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**要点**:
|
|
217
|
+
- 新增页签用 `virtualRow[tabLabelField] = "新增"` 作为初始标题,因为 x-tabs 标题绑定 `tab.data[tabLabelField]`,是响应式的。
|
|
218
|
+
- `tabName = "add_" + Date.now()` 保证每次新增都是新页签(不去重)。
|
|
219
|
+
- `tabLabelField` 必须配置(即 `multiTabLabelField`),否则无法显示标题;UI 上可加校验提示。
|
|
220
|
+
|
|
221
|
+
### 4.3 改造点 3:`list.vue` 的 `reload` 回调更新页签标题
|
|
222
|
+
|
|
223
|
+
**文件**:`src/views/user/form/view/list.vue`(reload 方法,需定位)
|
|
224
|
+
|
|
225
|
+
**目的**:保存成功后 `defaultHandle.js` 会调 `reloadForm({updateParam:{dataId, formCode}})` → emit "reload" → list.vue 的 reload 接收。在此处把当前新增页签的标题从「新增」改为单号。
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
reload(target, param) {
|
|
229
|
+
// 现有逻辑保持不变 ...
|
|
230
|
+
|
|
231
|
+
// ★ 新增:若当前活动页签是新增页签(tabName 以 "add_" 开头),
|
|
232
|
+
// 且 param.updateParam.dataId 有值,更新该页签的标题字段为单号
|
|
233
|
+
let updateParam = param?.updateParam;
|
|
234
|
+
let newDataId = updateParam?.dataId;
|
|
235
|
+
if (newDataId && this.$refs.xTabs) {
|
|
236
|
+
let activeName = this.$refs.xTabs.activeName;
|
|
237
|
+
let tab = this.$refs.xTabs.tabs.find(t => t.tabName === activeName);
|
|
238
|
+
if (tab && /^add_/.test(tab.tabName) && tab.tabLabelField) {
|
|
239
|
+
// 1. 更新标题字段 → 响应式触发 tab label 变单号
|
|
240
|
+
this.$set(tab.data, tab.tabLabelField, newDataId);
|
|
241
|
+
// 2. 更新 dataId(后续编辑/提交要用)
|
|
242
|
+
tab.dataId = newDataId;
|
|
243
|
+
// 3. 同步 formCode 到编辑表单(如果配置了 editFormCode)
|
|
244
|
+
if (updateParam.formCode) tab.formCode = updateParam.formCode;
|
|
245
|
+
// 4. (可选)更新 tabName 保持一致性,避免后续重复开同单号页签
|
|
246
|
+
// 注意:改 tabName 需同步 el-tabs 的 name,谨慎处理;可不改,靠 dataId 去重
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 现有的表单刷新逻辑(reloadForm 透传)保持不变 ...
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**要点**:
|
|
255
|
+
- 用 `this.$set` 确保 Vue 2 响应式触发标题更新。
|
|
256
|
+
- 标题字段值 = 单号 = `res.objx`,与编辑页签的标题来源一致,视觉上自然过渡。
|
|
257
|
+
- `reloadForm` 本身已通过 `updateParam` 把 `dataId`/`formCode` 透传给 `vFormRender`,表单会重新加载编辑表单和数据 → **编辑界面自动切换**,无需额外处理。
|
|
258
|
+
|
|
259
|
+
### 4.4 改造点 4:`defaultHandle.js` 的 `saveAndSubmitWfHandle` 按配置分支
|
|
260
|
+
|
|
261
|
+
**文件**:`src/components/xform/mixins/defaultHandle.js`(L113-152)
|
|
262
|
+
|
|
263
|
+
**现状**:`openStartWfDialog` 未传 `onStartSuccess`,wf.js 默认走 `$baseReload()`(刷新当前页)。
|
|
264
|
+
|
|
265
|
+
**改造**:根据 `formConfig.submitBehavior` 注入 `onStartSuccess`:
|
|
266
|
+
|
|
267
|
+
```js
|
|
268
|
+
saveAndSubmitWfHandle(option) {
|
|
269
|
+
let formRef = this.getFormRef ? this.getFormRef() : this;
|
|
270
|
+
let formConfig = formRef.formConfig;
|
|
271
|
+
let reportTemplate = formRef.reportTemplate;
|
|
272
|
+
// ... 现有校验不变
|
|
273
|
+
|
|
274
|
+
let submitBehavior = formConfig.submitBehavior || "closeToList";
|
|
275
|
+
|
|
276
|
+
this.saveDefaultHandle({
|
|
277
|
+
...option,
|
|
278
|
+
config: {
|
|
279
|
+
...option?.config,
|
|
280
|
+
successMsg: option?.config?.successMsg ?? true,
|
|
281
|
+
isConfirm: option?.config?.isConfirm ?? true,
|
|
282
|
+
confirmText: option?.config?.confirmText || confirmText,
|
|
283
|
+
success: (res) => {
|
|
284
|
+
openStartWfDialog(formRef, {
|
|
285
|
+
objId: res.objx,
|
|
286
|
+
wfCode: reportTemplate.objTypeCode,
|
|
287
|
+
formCode: reportTemplate.formCode,
|
|
288
|
+
serviceId: reportTemplate.serviceName,
|
|
289
|
+
skipStartConfirm: true,
|
|
290
|
+
// ★ 新增:注入流程启动成功回调
|
|
291
|
+
onStartSuccess: () => {
|
|
292
|
+
if (submitBehavior === "refreshCurrent") {
|
|
293
|
+
// 行为A:刷新当前页签(保持编辑态)—— 现有默认行为
|
|
294
|
+
formRef.$baseReload();
|
|
295
|
+
} else {
|
|
296
|
+
// 行为B:关闭当前页签 → 切列表 → 刷新列表
|
|
297
|
+
// 复用 indexMixin.js 的 switchToListTab
|
|
298
|
+
// 并显式关闭当前 x-tabs 页签
|
|
299
|
+
formRef.switchToListTab({ handleType: "reload" });
|
|
300
|
+
// switchToListTab 只切到列表页签,不关当前页签;
|
|
301
|
+
// 若要"关闭当前页签",需额外调 xTabs.removeTab(currentTabName)
|
|
302
|
+
let listPageRef = formRef.getListPageRef?.();
|
|
303
|
+
let xTabs = listPageRef?.$refs?.xTabs;
|
|
304
|
+
let currentName = xTabs?.activeName;
|
|
305
|
+
if (xTabs && currentName && /^add_|edit_/.test(currentName)) {
|
|
306
|
+
xTabs.removeTab(currentName);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
option?.config?.onStartSuccess?.();
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
option?.config?.success && option.config.success(res);
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**要点**:
|
|
320
|
+
- `submitBehavior === "refreshCurrent"`:等价于现状(`$baseReload`),保持编辑态。
|
|
321
|
+
- `submitBehavior === "closeToList"`:①`switchToListTab({handleType:"reload"})` 切列表并刷新;②额外 `xTabs.removeTab(currentName)` 关闭当前新增/编辑页签。
|
|
322
|
+
- `switchToListTab` 和 `getListPageRef` 都在 `indexMixin.js` 已有,`formRef`(vFormRender 实例)通过 mixin 拥有这些方法。
|
|
323
|
+
- 关闭页签前用正则判断当前是动态页签(`add_`/`edit_`),避免误关列表页签。
|
|
324
|
+
|
|
325
|
+
### 4.5 改造点 5(可选):`wf.js` 的 `startSubmitHanlde` 透传 `onStartSuccess`
|
|
326
|
+
|
|
327
|
+
**文件**:`src/components/wf/wf.js`(L1817-1852)
|
|
328
|
+
|
|
329
|
+
**现状**(探索报告):
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
callback: (resultMsg) => {
|
|
333
|
+
if (resultMsg.type == "success") {
|
|
334
|
+
that.$message({
|
|
335
|
+
message: resultMsg.content, type: "success", duration: 500,
|
|
336
|
+
onClose: (t) => {
|
|
337
|
+
if (!option.onStartSuccess) {
|
|
338
|
+
that.$baseReload(); // 默认刷新当前页
|
|
339
|
+
} else {
|
|
340
|
+
option.onStartSuccess(); // 自定义回调
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**结论**:wf.js **已支持** `onStartSuccess` 钩子,**无需改动**。只需在 `defaultHandle.js` 的 `openStartWfDialog` 调用里传入即可(见 4.4)。
|
|
349
|
+
|
|
350
|
+
> ⚠️ 需验证 `openStartWfDialog` 是否把 `option.onStartSuccess` 透传给 `startSubmitHanlde`。若未透传,需在 `openStartWfDialog` 内补一行透传(属小改)。落地时第一步先确认此处。
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 五、端到端流程图解
|
|
355
|
+
|
|
356
|
+
### 5.1 新增 → 保存 → 编辑态
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
用户点[新增]按钮
|
|
360
|
+
│
|
|
361
|
+
▼
|
|
362
|
+
list.vue openEditDialog(row={id:null}, ...)
|
|
363
|
+
│ addTabEnabled=true && !dataId && tabLabelField
|
|
364
|
+
▼
|
|
365
|
+
xTabs.openEditTab(virtualRow={[tabLabelField]:"新增"}, param, {tabParam:{tabName:"add_xxx"}})
|
|
366
|
+
│ → 创建可关闭页签,标题="新增",渲染 addFormCode 表单
|
|
367
|
+
▼
|
|
368
|
+
用户填写表单 → 点[保存]
|
|
369
|
+
│
|
|
370
|
+
▼
|
|
371
|
+
defaultHandle.saveDefaultHandle
|
|
372
|
+
│ success: res.objx = 单号
|
|
373
|
+
▼
|
|
374
|
+
formRef.reloadForm({updateParam:{dataId:单号, formCode:editFormCode}})
|
|
375
|
+
│ → emit("reload", this, {updateParam})
|
|
376
|
+
▼
|
|
377
|
+
list.vue reload(target, param)
|
|
378
|
+
│ ★ 检测当前 tabName 以 "add_" 开头
|
|
379
|
+
│ ★ $set(tab.data, tabLabelField, 单号) → 标题响应式变单号
|
|
380
|
+
│ ★ tab.dataId = 单号; tab.formCode = editFormCode
|
|
381
|
+
▼
|
|
382
|
+
vFormRender 收到 updateParam → 重新加载编辑表单 + 拉取已存数据
|
|
383
|
+
│
|
|
384
|
+
▼
|
|
385
|
+
页面保持在同一页签,标题=单号,表单=编辑态 ✅
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 5.2 提交(启动流程)→ closeToList
|
|
389
|
+
|
|
390
|
+
```
|
|
391
|
+
用户点[提交](或保存并提交)
|
|
392
|
+
│
|
|
393
|
+
▼
|
|
394
|
+
defaultHandle.saveAndSubmitWfHandle
|
|
395
|
+
│ success: openStartWfDialog({..., onStartSuccess})
|
|
396
|
+
▼
|
|
397
|
+
wf.js startSubmitHanlde → 流程启动成功
|
|
398
|
+
│ → option.onStartSuccess()
|
|
399
|
+
▼
|
|
400
|
+
submitBehavior === "closeToList" 分支
|
|
401
|
+
│ ① formRef.switchToListTab({handleType:"reload"})
|
|
402
|
+
│ → activeName="second" + 刷新列表
|
|
403
|
+
│ ② xTabs.removeTab(currentName) // 关闭当前 add_/edit_ 页签
|
|
404
|
+
▼
|
|
405
|
+
用户回到列表页签,看到最新列表,原新增/编辑页签已关闭 ✅
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### 5.3 提交(启动流程)→ refreshCurrent
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
submitBehavior === "refreshCurrent" 分支
|
|
412
|
+
│ formRef.$baseReload()
|
|
413
|
+
▼
|
|
414
|
+
当前页签内容刷新,保持编辑态(标题仍为单号) ✅
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## 六、兼容性与回退
|
|
420
|
+
|
|
421
|
+
### 6.1 向后兼容
|
|
422
|
+
|
|
423
|
+
| 场景 | 旧表单(未配置新字段) | 新表单(启用本模式) |
|
|
424
|
+
|------|----------------------|--------------------|
|
|
425
|
+
| `addTabEnabled` 未设置 / false | 新增走「常规」页签,行为完全不变 | — |
|
|
426
|
+
| `addTabEnabled = true` | — | 新增开独立页签 |
|
|
427
|
+
| `submitBehavior` 未设置 | 默认 `"closeToList"`,但仅在 `addTabEnabled` 或 `wfEnabled` 时生效;旧表单 `wfEnabled=false` 不触发提交分支 | 按配置 |
|
|
428
|
+
| `multiTabEnabled` | 编辑页签多开,语义不变 | 与 `addTabEnabled` 可叠加 |
|
|
429
|
+
|
|
430
|
+
**结论**:所有新字段默认值都保证旧表单零行为变化,可灰度上线。
|
|
431
|
+
|
|
432
|
+
### 6.2 回退方案
|
|
433
|
+
|
|
434
|
+
- **配置回退**:把 `addTabEnabled` 关掉即恢复「常规」页签模式,无需改代码。
|
|
435
|
+
- **代码回退**:5 个改造点均为**新增分支**,未删除/修改现有逻辑分支(除 4.4 在 `openStartWfDialog` 多传一个 `onStartSuccess` 参数)。回退只需 revert 改动文件。
|
|
436
|
+
|
|
437
|
+
### 6.3 已知风险与注意事项
|
|
438
|
+
|
|
439
|
+
| 风险点 | 影响 | 应对 |
|
|
440
|
+
|--------|------|------|
|
|
441
|
+
| `tabLabelField`(即 `multiTabLabelField`)未配置 | 新增页签无标题,x-tabs 可能渲染空 label | UI 上 `addTabEnabled=true` 时校验必填 `multiTabLabelField`,或默认用 `addTabLabel` 兜底 |
|
|
442
|
+
| 新增页签 `tabName` 用 `Date.now()`,快速双击新增可能撞名 | 极低概率 | 改用 `add_${Date.now()}_${Math.random().toString(36).slice(2,6)}` |
|
|
443
|
+
| `openStartWfDialog` 未透传 `onStartSuccess` 到 `startSubmitHanlde` | 提交后行为配置失效,退化为默认 `$baseReload` | 落地第一步先验证此处透传链路,必要时在 `openStartWfDialog` 补透传 |
|
|
444
|
+
| 保存后改了 `tab.data[tabLabelField]` 但 `tabName` 仍为 `add_xxx` | 同一单号再次从列表打开编辑页签时,`openEditTab` 按 `row[paneKeyName]` 去重可能失效(因为新增页签 tabName 不是 `formCode+dataId`) | 保存后同步把 `tabName` 改为 `formCode+dataId`;或接受"可能重复开",由 `multiTabEnabled` 的编辑去重兜底 |
|
|
445
|
+
| 「常规」页签(name="first")仍存在于 DOM | 视觉上可能多一个空页签 | 当 `addTabEnabled=true` 时,用 `v-if` 隐藏「常规」pane;或保持不变(不激活用户看不到) |
|
|
446
|
+
| 移动端 H5(`layoutType=="H5"`)走 `openEditH5Dialog`,不走 x-tabs | 本模式在 H5 不生效 | UI 上 `addTabEnabled` 仅对 PC 生效,H5 仍走原 `openEditH5Dialog`;文档注明 |
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 七、实施步骤建议
|
|
451
|
+
|
|
452
|
+
### Phase 1:配置项骨架(0.5 天)
|
|
453
|
+
1. `designer.js` 加 3 个默认字段
|
|
454
|
+
2. `form-setting.vue` 加「页签交互模式」collapse 分组
|
|
455
|
+
3. 验证:设计器能配置并保存到 formJson
|
|
456
|
+
|
|
457
|
+
### Phase 2:新增页签打开(0.5 天)
|
|
458
|
+
1. `list.vue` `openEditDialog` 增加 `addTabEnabled` 分支
|
|
459
|
+
2. 验证:点新增能开标题为「新增」的可关闭页签,渲染新增表单
|
|
460
|
+
|
|
461
|
+
### Phase 3:保存后变编辑态(0.5 天)
|
|
462
|
+
1. `list.vue` `reload` 回调增加页签标题更新逻辑
|
|
463
|
+
2. 验证:保存后页签标题变单号,表单切到编辑态,dataId 正确
|
|
464
|
+
|
|
465
|
+
### Phase 4:提交后行为配置(0.5 天)
|
|
466
|
+
1. 先验证 `openStartWfDialog` → `startSubmitHanlde` 的 `onStartSuccess` 透传链路
|
|
467
|
+
2. `defaultHandle.js` `saveAndSubmitWfHandle` 注入按 `submitBehavior` 分支的回调
|
|
468
|
+
3. 验证:`closeToList` 关页签回列表刷新;`refreshCurrent` 刷新当前页
|
|
469
|
+
|
|
470
|
+
### Phase 5:边界与体验(0.5 天)
|
|
471
|
+
1. `tabLabelField` 必填校验 + 兜底
|
|
472
|
+
2. 「常规」pane 在 `addTabEnabled=true` 时的显隐
|
|
473
|
+
3. H5 场景的兼容处理
|
|
474
|
+
4. 多次新增、保存后再次编辑、提交后再次打开同单号等边界测试
|
|
475
|
+
|
|
476
|
+
**合计约 2.5 天**。
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## 八、测试要点清单
|
|
481
|
+
|
|
482
|
+
| # | 场景 | 预期 |
|
|
483
|
+
|---|------|------|
|
|
484
|
+
| 1 | 旧表单(未启用本模式)点新增 | 走「常规」页签,行为不变 |
|
|
485
|
+
| 2 | 启用本模式,点新增 | 开标题「新增」可关闭页签 |
|
|
486
|
+
| 3 | 新增页签填写后保存 | 标题变单号,表单变编辑态,不新开页签 |
|
|
487
|
+
| 4 | 新增页签直接关闭(不保存) | 页签正常关闭,不影响列表 |
|
|
488
|
+
| 5 | 编辑页签(multiTabEnabled)仍正常 | 不受影响 |
|
|
489
|
+
| 6 | 提交,`submitBehavior=closeToList` | 当前页签关闭,切列表,列表刷新 |
|
|
490
|
+
| 7 | 提交,`submitBehavior=refreshCurrent` | 当前页签刷新,保持编辑态 |
|
|
491
|
+
| 8 | 同一单号从列表再次打开编辑 | 不重复开页签(去重生效) |
|
|
492
|
+
| 9 | H5 端访问 | 走 `openEditH5Dialog`,不报错 |
|
|
493
|
+
| 10 | `tabLabelField` 未配置 | 给提示或用 `addTabLabel` 兜底,不崩 |
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## 九、附录:关键文件锚点速查
|
|
498
|
+
|
|
499
|
+
| 锚点 | 位置 |
|
|
500
|
+
|------|------|
|
|
501
|
+
| 「常规」页签定义 | `src/views/user/form/view/list.vue:10` |
|
|
502
|
+
| `openEditDialog` 新增/编辑分支 | `src/views/user/form/view/list.vue:269-319` |
|
|
503
|
+
| `formConfig` 默认值 | `src/components/xform/form-designer/designer.js:51-108` |
|
|
504
|
+
| 配置 UI collapse 分组 | `src/components/xform/form-designer/setting-panel/form-setting.vue:211-273`(name=4,5) |
|
|
505
|
+
| `saveDefaultHandle` | `src/components/xform/mixins/defaultHandle.js:153-199` |
|
|
506
|
+
| `saveAndSubmitWfHandle` | `src/components/xform/mixins/defaultHandle.js:113-152` |
|
|
507
|
+
| `reloadForm` | `src/components/xform/form-render/indexMixin.js:2792-2806` |
|
|
508
|
+
| `switchToListTab` / `getListPageRef` | `src/components/xform/form-render/indexMixin.js:2734-2791` |
|
|
509
|
+
| 流程启动回调 | `src/components/wf/wf.js:1817-1852` |
|
|
510
|
+
| x-tabs `openEditTab` / `removeTab` | `src/components/vb-tabs/x-tabs.vue` |
|
|
511
|
+
| 弃用的 Vue3 草案 | `src/components/xform/XFormTabContainer/IMPLEMENTATION_PLAN.md` |
|