cloud-web-corejs 1.0.54-dev.788 → 1.0.54-dev.789

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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloud-web-corejs",
3
3
  "private": false,
4
- "version": "1.0.54-dev.788",
4
+ "version": "1.0.54-dev.789",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "dev:micro": "vue-cli-service serve --port 17527",
@@ -69,7 +69,6 @@
69
69
  | `compareToList(list1, list2)` | 编码列表匹配,空列表表示不限 |
70
70
  | `hasTextMaskRule(widgetOptions)` | 是否配了有效规则(不代表当前用户命中) |
71
71
  | `buildTextMaskContext(formRef, companyCode)` | 组装 `{ bdService, companyCode, roleCodeList }` |
72
- | `isTextMaskContextReady(ctx)` | 上下文是否就绪 |
73
72
  | `markMaskedExportColumns($grid, ctx)` | 给命中列打 `params.exportDisabled`,并同步到明细导出列 |
74
73
 
75
74
  判定逻辑逐行照搬原 `initShowType`,包括两个易被"优化"掉的细节:
@@ -108,11 +107,11 @@ H5 列表容器有独立 `exportData`,同样处理。这是编码阶段才发
108
107
  **决策 1 —— 判定放在导出触发时,不放在建列时。**
109
108
  `bdService` / `userRoleDTOs` 由异步接口填充(`form-render/indexMixin.js:458、479、498`),建列时可能尚未就绪。
110
109
 
111
- **决策 2 —— 上下文未就绪时 fail-closed。**
112
- `compareToList` 在角色列表为空时返回 false → 被判成"角色不匹配":对 `type=1` 规则偏保守(判为脱敏,安全),但对 `type=2` 规则会判成**不脱敏**,正好是危险方向。故上下文未就绪时,凡 `hasTextMaskRule` 为真的列一律剔除。
110
+ **决策 2 —— 不做"上下文未就绪"的收紧判断(踩过坑,见第十节)。**
111
+ 判定结论与渲染层严格一致即可:同一个 `resolveTextMaskFlag`、同一份用户上下文,且导出必然发生在单元格渲染之后(用户已经看到明文或密文)。**不要再引入任何"上下文是否就绪"的启发式**。
113
112
 
114
113
  **决策 3 —— `mounted` 也标记一次。**
115
- vxe 原生导出不走 `exportData()`,若只在导出入口标记,`columnFilterMethod` 会拿到一张没标记的列表,等于没堵。建列后立刻按 fail-closed 打标,之后每次 `exportData` 自愈修正。用户先点 $excelExport 再点原生导出的顺序也天然安全。
114
+ vxe 原生导出不走 `exportData()`,若只在导出入口标记,`columnFilterMethod` 会拿到一张没标记的列表,等于没堵。故建列后先按当时的上下文标记一次;此刻结论未必准,但只会"少防护"不会误伤,之后每次 `exportData` 会按最新上下文自愈修正。
116
115
 
117
116
  **决策 4 —— 标记幂等且可自愈,用私有键区分归属。**
118
117
  `exportDisabled` 也可能是 `isNonDataExportColumn`(`data-table-mixin.js:1710`)打的。若无差别地 `delete`,自愈会误放行操作列。故引入 `MASK_MARK_KEY = "exportDisabledByTextMask"`(`textMaskUtil.js:19`):
@@ -146,7 +145,7 @@ vxe 原生导出不走 `exportData()`,若只在导出入口标记,`columnFil
146
145
 
147
146
  已验证:
148
147
 
149
- - `npx jest`:13 套 156 个用例全过(新增 17 个)
148
+ - `npx jest`:13 套 157 个用例全过(新增 18 个)
150
149
  - ESLint:新增文件 0 error;改动文件只剩改动前就存在的既有错误(全库 132 个,`npm run lint` 本就不通过)
151
150
 
152
151
  **未做真机联调**,以下回归项待验:
@@ -155,11 +154,20 @@ vxe 原生导出不走 `exportData()`,若只在导出入口标记,`columnFil
155
154
  2. 两种规则方向:`type=2 + 角色匹配`、`type=1 + 角色不匹配`;
156
155
  3. 未配脱敏的列完全不受影响;
157
156
  4. **分组表头 2 层 / 3 层下剔除叶子列后表头不错位**(`loopDo` 会重算 `colSpan/rowSpan`,本轮风险最高的一处);
158
- 5. 用户信息接口未返回时立即点导出 走 fail-closed 而非明文导出;
159
- 6. 页面遮罩显示效果与改造前一致(验证 `initShowType` 重构无回归);
160
- 7. vxe 工具栏导出(若宿主开启了该按钮)。
157
+ 5. 页面遮罩显示效果与改造前一致(验证 `initShowType` 重构无回归);
158
+ 6. vxe 工具栏导出(若宿主开启了该按钮)。
161
159
 
162
- ## 九、同步提示
160
+ ## 九、联调发现的问题(2026-08-04,已修)
161
+
162
+ **现象**:配了规则后,部分用户看明文、部分看密文(符合预期),但**所有用户导出时该列都消失**。
163
+
164
+ **根因**:首版实现有一个 `isTextMaskContextReady(ctx)`,用 `ctx.bdService` 非空 + 角色列表非空当作"用户上下文已就绪"的判据,未就绪时 fail-closed 剔除整列。但 `bdService` 来自 `/form_develop/getBdService`(`indexMixin.js:489`),`res.objx` 在大量环境本就是空值 —— 于是 `contextReady` 恒为 false,凡配了规则的列对所有用户一律被剔除。
165
+
166
+ **修复**:删除 `isTextMaskContextReady`,`markMaskedExportColumns` 直接采用 `resolveTextMaskFlag` 的结论。
167
+
168
+ **教训**:fail-closed 本身没错,错在"就绪"判据是拿业务值反推运行状态的启发式。这里根本不需要它 —— 渲染层用同一函数、同一上下文,且导出必然晚于渲染,结论天然一致;页面显示什么,导出就该按什么处理。回归用例见 spec 中「bdService 为空时结论仍只由规则决定」。
169
+
170
+ ## 十、同步提示
163
171
 
164
172
  - `textMaskUtil.js` 属包内新增文件,海尔分支(stdxx)整体覆盖时需一并带上,否则 `form-item-wrapper.vue` 与两个容器的 import 会解析失败;
165
173
  - 改动 5 落在 `components/table/index.js`(通用表格默认配置),影响面超出 xform,同步时注意与分支上的本地修改合并。
@@ -247,8 +247,8 @@ modules = {
247
247
  this.bootstrapDynamicColumnsBeforeInit().then(() => {
248
248
  this.initColumnWidgetConfig(() => {
249
249
  this.initTableList();
250
- // 让不走 $excelExport 的旁路(vxe 工具栏自带导出)也受控:此刻用户上下文
251
- // 多半尚未就绪,按 fail-closed 先剔除,之后每次 exportData 会自愈修正
250
+ // 让不走 $excelExport 的旁路(vxe 工具栏自带导出)也受控。此刻用户上下文
251
+ // 可能尚未就绪,结论未必准,之后每次 exportData 会按最新上下文自愈修正
252
252
  this.$nextTick(() => {
253
253
  this.markMaskedColumnsForExport();
254
254
  });
@@ -62,14 +62,6 @@ export function buildTextMaskContext(formRef, companyCode) {
62
62
  };
63
63
  }
64
64
 
65
- /**
66
- * @param {Object} ctx 判定上下文。
67
- * @returns {Boolean} 用户上下文是否已就绪(bdService / 角色均由异步接口填充)。
68
- */
69
- export function isTextMaskContextReady(ctx) {
70
- return !!ctx?.bdService && !!(ctx?.roleCodeList || []).length;
71
- }
72
-
73
65
  /**
74
66
  * @param {Object} widgetOptions 组件 options。
75
67
  * @param {Object} ctx 用户上下文 { bdService, companyCode, roleCodeList }。
@@ -122,10 +114,13 @@ export function resolveTextMaskFlag(widgetOptions, ctx) {
122
114
  * 之所以要按列剔除:命中脱敏规则的字段在界面上只渲染掩码文本,但导出取值走
123
115
  * filterVal / 原始字段快路径,不经过渲染层,会把明文写进文件。
124
116
  *
125
- * bdService / userRoleDTOs 由异步接口填充,上下文缺失时按 fail-closed 处理——配了
126
- * 规则的列一律剔除,因为角色列表为空会被判成"角色不匹配",type=2 的规则会误判为
127
- * 不脱敏。本函数幂等且可自愈:上下文就绪后重复调用会撤销自己此前多打的标记
128
- * (靠私有键区分,不碰 isNonDataExportColumn 打的标记)。
117
+ * 判定结论与渲染层严格一致:同一个 resolveTextMaskFlag、同一份用户上下文,且导出
118
+ * 必然发生在单元格渲染之后(用户已看到明文或密文),所以不做"上下文未就绪"的收紧。
119
+ * 曾用 bdService 非空当就绪判据并 fail-closed,但该字段来自 getBdService 接口、
120
+ * 大量环境本就返回空,导致所有用户的脱敏列被一律剔除——不要再加这类启发式。
121
+ *
122
+ * 本函数幂等且可自愈:结论变化时会撤销自己此前打的标记(靠私有键区分,不碰
123
+ * isNonDataExportColumn 打的标记)。
129
124
  *
130
125
  * @param {Object} $grid vxe-grid 实例。
131
126
  * @param {Object} ctx 判定上下文,由 buildTextMaskContext 生成。
@@ -133,15 +128,13 @@ export function resolveTextMaskFlag(widgetOptions, ctx) {
133
128
  export function markMaskedExportColumns($grid, ctx) {
134
129
  if (!$grid || typeof $grid.getTableColumn !== "function") return;
135
130
 
136
- let contextReady = isTextMaskContextReady(ctx);
137
-
138
131
  /** 打标记。列本就被其它规则(isNonDataExportColumn)剔除时不接管,避免撤销时误删。 */
139
132
  let disable = (params) => {
140
133
  if (params.exportDisabled && !params[MASK_MARK_KEY]) return;
141
134
  params.exportDisabled = true;
142
135
  params[MASK_MARK_KEY] = true;
143
136
  };
144
- /** 撤销本函数此前打的标记(上下文未就绪时的 fail-closed 结论)。 */
137
+ /** 撤销本函数此前打的标记(判定结论变化时)。 */
145
138
  let restore = (params) => {
146
139
  if (!params[MASK_MARK_KEY]) return;
147
140
  delete params[MASK_MARK_KEY];
@@ -156,7 +149,7 @@ export function markMaskedExportColumns($grid, ctx) {
156
149
  }
157
150
  let widgetOptions = column.params?.widget?.options;
158
151
  if (!hasTextMaskRule(widgetOptions)) return;
159
- if (contextReady && !resolveTextMaskFlag(widgetOptions, ctx).masked) {
152
+ if (!resolveTextMaskFlag(widgetOptions, ctx).masked) {
160
153
  restore(column.params);
161
154
  return;
162
155
  }