eoss 0.1.0-alpha.39 → 0.1.0-alpha.40

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.
Files changed (233) hide show
  1. package/lib/0.js +1 -1
  2. package/lib/1.js +1 -1
  3. package/lib/10.js +1 -1
  4. package/lib/11.js +1 -1
  5. package/lib/12.js +1 -1
  6. package/lib/13.js +1 -1
  7. package/lib/14.js +1 -1
  8. package/lib/15.js +1 -1
  9. package/lib/16.js +1 -1
  10. package/lib/17.js +1 -1
  11. package/lib/18.js +1 -1
  12. package/lib/19.js +1 -1
  13. package/lib/20.js +1 -1
  14. package/lib/21.js +1 -1
  15. package/lib/22.js +1 -1
  16. package/lib/23.js +1 -1
  17. package/lib/24.js +1 -1
  18. package/lib/25.js +1 -1
  19. package/lib/26.js +1 -1
  20. package/lib/27.js +1 -1
  21. package/lib/28.js +1 -1
  22. package/lib/29.js +1 -1
  23. package/lib/3.js +1 -1
  24. package/lib/30.js +1 -1
  25. package/lib/31.js +1 -1
  26. package/lib/32.js +1 -1
  27. package/lib/33.js +1 -1
  28. package/lib/34.js +1 -1
  29. package/lib/35.js +1 -1
  30. package/lib/36.js +1 -1
  31. package/lib/37.js +1 -1
  32. package/lib/38.js +1 -1
  33. package/lib/39.js +1 -1
  34. package/lib/4.js +1 -1
  35. package/lib/40.js +1 -1
  36. package/lib/41.js +1 -1
  37. package/lib/42.js +1 -1
  38. package/lib/43.js +1 -1
  39. package/lib/44.js +1 -1
  40. package/lib/45.js +1 -1
  41. package/lib/46.js +1 -1
  42. package/lib/47.js +1 -1
  43. package/lib/48.js +1 -1
  44. package/lib/49.js +1 -1
  45. package/lib/5.js +1 -1
  46. package/lib/50.js +1 -1
  47. package/lib/51.js +1 -1
  48. package/lib/52.js +1 -1
  49. package/lib/53.js +1 -1
  50. package/lib/54.js +1 -1
  51. package/lib/55.js +1 -1
  52. package/lib/56.js +1 -1
  53. package/lib/57.js +1 -1
  54. package/lib/58.js +1 -1
  55. package/lib/59.js +1 -1
  56. package/lib/6.js +1 -1
  57. package/lib/60.js +1 -1
  58. package/lib/61.js +1 -1
  59. package/lib/62.js +1 -1
  60. package/lib/63.js +1 -1
  61. package/lib/64.js +1 -1
  62. package/lib/65.js +1 -1
  63. package/lib/66.js +1 -1
  64. package/lib/67.js +1 -1
  65. package/lib/68.js +1 -1
  66. package/lib/69.js +1 -1
  67. package/lib/7.js +1 -1
  68. package/lib/70.js +1 -1
  69. package/lib/71.js +1 -1
  70. package/lib/72.js +1 -1
  71. package/lib/73.js +1 -1
  72. package/lib/74.js +1 -1
  73. package/lib/75.js +1 -1
  74. package/lib/76.js +1 -1
  75. package/lib/77.js +1 -1
  76. package/lib/78.js +1 -1
  77. package/lib/79.js +1 -1
  78. package/lib/8.js +1 -1
  79. package/lib/80.js +1 -1
  80. package/lib/81.js +1 -1
  81. package/lib/9.js +1 -1
  82. package/lib/account-login.js +837 -862
  83. package/lib/alert.js +2 -2
  84. package/lib/aside.js +2 -2
  85. package/lib/audit-trajectory.js +4 -4
  86. package/lib/autocomplete.js +1813 -1988
  87. package/lib/avatar.js +2 -2
  88. package/lib/backtop.js +2 -2
  89. package/lib/badge.js +2 -2
  90. package/lib/breadcrumb-item.js +4 -4
  91. package/lib/breadcrumb.js +4 -4
  92. package/lib/button-group.js +4 -4
  93. package/lib/button.js +2 -2
  94. package/lib/ca-login.js +837 -862
  95. package/lib/calendar.js +839 -864
  96. package/lib/card.js +2 -2
  97. package/lib/carousel-item.js +846 -871
  98. package/lib/carousel.js +839 -864
  99. package/lib/cascader-panel.js +852 -877
  100. package/lib/cascader.js +2048 -2223
  101. package/lib/checkbox-button.js +4 -4
  102. package/lib/checkbox-group.js +859 -884
  103. package/lib/checkbox.js +4 -4
  104. package/lib/col.js +2 -2
  105. package/lib/collapse-item.js +1040 -1065
  106. package/lib/collapse.js +1040 -1065
  107. package/lib/color-picker.js +972 -1122
  108. package/lib/container.js +2 -2
  109. package/lib/cron.js +12 -12
  110. package/lib/data-table.js +843 -868
  111. package/lib/date-picker.js +10520 -10695
  112. package/lib/descriptions-item.js +4 -4
  113. package/lib/descriptions.js +4 -4
  114. package/lib/dialog.js +837 -862
  115. package/lib/divider.js +2 -2
  116. package/lib/drawer.js +2 -2
  117. package/lib/dropdown-item.js +4 -4
  118. package/lib/dropdown-menu.js +974 -1124
  119. package/lib/dropdown.js +841 -866
  120. package/lib/email-login.js +837 -862
  121. package/lib/empty.js +2 -2
  122. package/lib/eoss.common.js +4023 -2668
  123. package/lib/flip.js +2 -2
  124. package/lib/flow-group.js +853 -878
  125. package/lib/flow.js +868 -893
  126. package/lib/flows.js +854 -879
  127. package/lib/footer.js +2 -2
  128. package/lib/form-item.js +860 -885
  129. package/lib/form.js +933 -950
  130. package/lib/guide.js +2 -2
  131. package/lib/header.js +2 -2
  132. package/lib/icon.js +837 -862
  133. package/lib/icons.js +2 -2
  134. package/lib/image-viewer.js +837 -862
  135. package/lib/image.js +4 -4
  136. package/lib/index.js +1 -1
  137. package/lib/infinite-scroll.js +2 -2
  138. package/lib/input-number.js +6 -6
  139. package/lib/input.js +839 -864
  140. package/lib/link.js +2 -2
  141. package/lib/loading.js +2 -2
  142. package/lib/login.js +867 -891
  143. package/lib/lowcode-view.js +1843 -1185
  144. package/lib/lowcode.js +3050 -1569
  145. package/lib/main.js +970 -988
  146. package/lib/marquee.js +837 -862
  147. package/lib/menu-item-group.js +15 -15
  148. package/lib/menu-item.js +6 -6
  149. package/lib/menu.js +2227 -2368
  150. package/lib/message-box.js +843 -868
  151. package/lib/message.js +839 -864
  152. package/lib/notification.js +861 -886
  153. package/lib/option-group.js +4 -4
  154. package/lib/option.js +839 -864
  155. package/lib/page-header.js +2 -2
  156. package/lib/pagination.js +839 -864
  157. package/lib/phone-login.js +847 -866
  158. package/lib/popconfirm.js +4 -4
  159. package/lib/popover.js +1831 -2006
  160. package/lib/process-config.js +839 -864
  161. package/lib/process-module.js +846 -871
  162. package/lib/process-rule.js +905 -930
  163. package/lib/progress.js +2 -2
  164. package/lib/qr-code.js +4 -4
  165. package/lib/qrcode-login.js +839 -864
  166. package/lib/radio-button.js +4 -4
  167. package/lib/radio-group.js +850 -875
  168. package/lib/radio.js +4 -4
  169. package/lib/rate.js +837 -862
  170. package/lib/retrial-auth.js +837 -862
  171. package/lib/row.js +2 -2
  172. package/lib/scrollbar.js +839 -864
  173. package/lib/select.js +2139 -2314
  174. package/lib/selector-panel.js +940 -965
  175. package/lib/selector.js +852 -877
  176. package/lib/slider.js +4 -4
  177. package/lib/step.js +32 -32
  178. package/lib/steps.js +874 -899
  179. package/lib/submenu.js +1269 -1385
  180. package/lib/switch.js +839 -864
  181. package/lib/tab-pane.js +4 -4
  182. package/lib/table-column.js +840 -865
  183. package/lib/table.js +1825 -2000
  184. package/lib/tabs.js +846 -871
  185. package/lib/tag.js +2 -2
  186. package/lib/theme-chalk/fonts/iconfont.ttf +0 -0
  187. package/lib/theme-chalk/fonts/iconfont.woff +0 -0
  188. package/lib/theme-chalk/index.css +1 -1
  189. package/lib/theme-chalk/lowcode.css +1 -1
  190. package/lib/time-picker.js +6471 -6646
  191. package/lib/time-select.js +5039 -5214
  192. package/lib/timeline-item.js +2 -2
  193. package/lib/timeline.js +2 -2
  194. package/lib/tips.js +837 -862
  195. package/lib/toolbar.js +4 -4
  196. package/lib/tooltip.js +1813 -1988
  197. package/lib/transfer.js +837 -862
  198. package/lib/tree-group.js +853 -878
  199. package/lib/tree.js +1026 -1051
  200. package/lib/update-history.js +4 -4
  201. package/lib/upload.js +859 -884
  202. package/lib/wujie.js +841 -866
  203. package/package.json +1 -1
  204. package/packages/flow-group/src/main.vue +2 -2
  205. package/packages/form/src/form-item-render.vue +1 -0
  206. package/packages/form/src/form-item.vue +12 -6
  207. package/packages/form/src/form.vue +5 -5
  208. package/packages/login/src/login.vue +1 -0
  209. package/packages/lowcode/src/attribute/function.vue +28 -9
  210. package/packages/lowcode/src/attribute/props.vue +202 -0
  211. package/packages/lowcode/src/attribute/styles.vue +79 -5
  212. package/packages/lowcode/src/attribute.vue +61 -4
  213. package/packages/lowcode/src/canvas.vue +159 -2
  214. package/packages/lowcode/src/form-render.vue +305 -0
  215. package/packages/lowcode/src/lowcode.vue +33 -13
  216. package/packages/lowcode/src/modules.vue +53 -37
  217. package/packages/lowcode/src/render.vue +80 -25
  218. package/packages/lowcode/src/util/components.js +100 -0
  219. package/packages/lowcode/src/util/props-util.js +67 -0
  220. package/packages/lowcode/src/util/source-generator.js +69 -9
  221. package/packages/lowcode/src/util/source-parser.js +64 -10
  222. package/packages/lowcode-view/src/render.vue +48 -18
  223. package/packages/main/src/components/userinfo.vue +0 -1
  224. package/packages/menu/src/menu-item-group.vue +1 -1
  225. package/packages/menu/src/mixins.js +8 -4
  226. package/packages/menu/src/submenu.vue +35 -5
  227. package/packages/phone-login/src/phone-login.vue +5 -2
  228. package/packages/theme-chalk/dist/fonts/iconfont.ttf +0 -0
  229. package/packages/theme-chalk/dist/fonts/iconfont.woff +0 -0
  230. package/packages/theme-chalk/src/fonts/iconfont.ttf +0 -0
  231. package/packages/theme-chalk/src/fonts/iconfont.woff +0 -0
  232. package/packages/theme-chalk/src/lowcode.scss +21 -2
  233. package/src/index.js +336 -336
@@ -0,0 +1,67 @@
1
+ /**
2
+ * 节点 props 定义数组与取值转换工具
3
+ *
4
+ * 节点 props 存定义数组:[{ name, type, default?, options?, value? }],
5
+ * value 仅在用户改动后写入条目;字符串取值支持 {{变量名}} 语法
6
+ * 引用页面 data 中定义的变量(整体匹配按变量绑定,局部匹配按插值)
7
+ */
8
+
9
+ /** 整体匹配 {{expr}} */
10
+ const FULL_VAR = /^\{\{([\s\S]+)\}\}$/;
11
+ /** 局部匹配 {{expr}} */
12
+ const PART_VAR = /\{\{([\s\S]+?)\}\}/g;
13
+
14
+ /** 按点路径从 data 中取变量值 */
15
+ function lookup(data, expr) {
16
+ if (!data || typeof data !== 'object') return undefined;
17
+ return expr.split('.').reduce((cur, key) => {
18
+ if (cur === undefined || cur === null) return undefined;
19
+ return cur[key];
20
+ }, data);
21
+ }
22
+
23
+ /** 解析字符串取值中的 {{变量}} 引用;非字符串原样返回 */
24
+ export function resolvePropValue(raw, data) {
25
+ if (typeof raw !== 'string' || raw.indexOf('{{') === -1) return raw;
26
+ const full = FULL_VAR.exec(raw);
27
+ if (full) return lookup(data, full[1].trim());
28
+ return raw.replace(PART_VAR, (all, expr) => {
29
+ const val = lookup(data, expr.trim());
30
+ return val === undefined || val === null ? '' : val;
31
+ });
32
+ }
33
+
34
+ /** 按名读取条目原始取值(value 优先、其次 default);兼容历史对象形态 */
35
+ export function getPropRaw(props, name) {
36
+ if (!props) return undefined;
37
+ if (!Array.isArray(props)) return props[name];
38
+ const item = props.find((p) => p && p.name === name);
39
+ if (!item) return undefined;
40
+ return item.value !== undefined ? item.value : item.default;
41
+ }
42
+
43
+ /**
44
+ * 定义数组 → 组件 v-bind 用的取值对象;
45
+ * 兼容历史对象形态 props(原样透传,跳过 v- 键)
46
+ */
47
+ export function propsToObject(props, data) {
48
+ if (!props) return {};
49
+ if (!Array.isArray(props)) {
50
+ const result = {};
51
+ Object.keys(props).forEach((key) => {
52
+ if (key.startsWith('v-')) return;
53
+ result[key] = props[key];
54
+ });
55
+ return result;
56
+ }
57
+ const result = {};
58
+ props.forEach((item) => {
59
+ if (!item || !item.name) return;
60
+ const raw = item.value !== undefined ? item.value : item.default;
61
+ if (raw === undefined) return;
62
+ const val = resolvePropValue(raw, data);
63
+ if (val === undefined) return;
64
+ result[item.name] = val;
65
+ });
66
+ return result;
67
+ }
@@ -80,12 +80,37 @@ function escapeAttr(val) {
80
80
  .replace(/"/g, '"');
81
81
  }
82
82
 
83
+ /** 单个 prop 属性串:{{var}} 整体匹配输出绑定表达式,其余按类型输出 */
84
+ function genPropAttr(key, val) {
85
+ if (typeof val === 'string') {
86
+ const full = /^\{\{([\s\S]+)\}\}$/.exec(val);
87
+ if (full) {
88
+ return ' :' + key + '="' + full[1].trim() + '"';
89
+ }
90
+ return ' ' + key + '="' + val + '"';
91
+ }
92
+ if (typeof val === 'boolean' || typeof val === 'number') {
93
+ return ' :' + key + '="' + val + '"';
94
+ }
95
+ // 复杂值用绑定语法输出:单引号属性 + 紧凑 JSON
96
+ return ' :' + key + "='" + JSON.stringify(val).replace(/'/g, ''') + "'";
97
+ }
98
+
83
99
  /** 生成节点的 props 属性串 */
84
100
  function genProps(node) {
85
101
  const props = node.props;
86
102
  if (!props) {
87
103
  return '';
88
104
  }
105
+ // 定义数组形态:仅输出值被改动过的条目(value 字段)
106
+ if (Array.isArray(props)) {
107
+ return props.reduce((attrs, item) => {
108
+ if (!item || !item.name || item.value === undefined) {
109
+ return attrs;
110
+ }
111
+ return attrs + genPropAttr(item.name, item.value);
112
+ }, '');
113
+ }
89
114
  return Object.keys(props).reduce((attrs, key) => {
90
115
  const val = props[key];
91
116
  if (val === undefined) {
@@ -186,6 +211,14 @@ function componentName(name) {
186
211
  });
187
212
  }
188
213
 
214
+ /** EsButton → es-button 形式的模板标签名(html 小写标签保持不变) */
215
+ function tagName(name) {
216
+ return String(name)
217
+ .replace(/([A-Z])/g, '-$1')
218
+ .toLowerCase()
219
+ .replace(/^-/, '');
220
+ }
221
+
189
222
  /** 递归收集节点树中的所有脚本依赖 */
190
223
  function collectScripts(node, scripts) {
191
224
  if (!node) return;
@@ -227,7 +260,7 @@ export function genNode(node, indent) {
227
260
  return '';
228
261
  }
229
262
  const pad = new Array(indent + 1).join(INDENT);
230
- const name = node.name || 'div';
263
+ const tag = tagName(node.name || 'div');
231
264
 
232
265
  // 节点 id 以 data-id 输出,源码编辑后能原样解析回来
233
266
  const idAttr = node.id ? ' data-id="' + node.id + '"' : '';
@@ -245,23 +278,50 @@ export function genNode(node, indent) {
245
278
  const vText = node.directives && node.directives['text'];
246
279
 
247
280
  if (!children.length && !vText) {
248
- lines.push(pad + '<' + name + attrStr + '></' + name + '>');
281
+ lines.push(pad + '<' + tag + attrStr + '></' + tag + '>');
249
282
  return lines.join('\n');
250
283
  }
251
- lines.push(pad + '<' + name + attrStr + '>');
284
+ lines.push(pad + '<' + tag + attrStr + '>');
252
285
  if (vText) {
253
286
  // v-text 属性转换为 {{xxx}} 形式
254
287
  lines.push(pad + INDENT + '{{' + vText + '}}');
255
- } else if (children.length) {
256
- // 子节点继续递归下钻
257
- children.forEach((child) => {
258
- lines.push(genNode(child, indent + 1));
259
- });
260
288
  }
261
- lines.push(pad + '</' + name + '>');
289
+ // 子节点继续递归下钻;带 formItem 标记的表单控件子节点输出时
290
+ // 包 es-form-item(JSON 不存包裹节点,源码与真实应用结构一一对应)
291
+ children.forEach((child) => {
292
+ lines.push(genChildNode(child, indent + 1));
293
+ });
294
+ lines.push(pad + '</' + tag + '>');
262
295
  return lines.join('\n');
263
296
  }
264
297
 
298
+ /** 生成子节点:表单控件(带 formItem)包 es-form-item 包裹层,其余直接生成 */
299
+ function genChildNode(child, indent) {
300
+ if (!child) {
301
+ return '';
302
+ }
303
+ if (!child.formItem) {
304
+ return genNode(child, indent);
305
+ }
306
+ const pad = new Array(indent + 1).join(INDENT);
307
+ const label = child.formItem.label || '';
308
+ const prop = child.formItem.prop || '';
309
+ // 宽度输出在包裹层:form-item 是列布局单元,拖宽占多列才能在真实应用生效;
310
+ // 内层控件不重复携带 width(画布上宽度同样作用于 es-form-item 根)
311
+ const width = child.style && child.style.width;
312
+ const styleAttr = width ? genStyle({ style: { width } }) : '';
313
+ let inner = child;
314
+ if (width) {
315
+ inner = { ...child, style: { ...child.style } };
316
+ delete inner.style.width;
317
+ }
318
+ return (
319
+ pad + '<es-form-item label="' + escapeAttr(label) + '" prop="' + escapeAttr(prop) + '"' + styleAttr + '>\n' +
320
+ genNode(inner, indent + 1) + '\n' +
321
+ pad + '</es-form-item>'
322
+ );
323
+ }
324
+
265
325
  /**
266
326
  * 生成 methods/computed/watch 等选项块
267
327
  * @param {string} name 选项名,如 computed 会生成计算属性 getter
@@ -76,6 +76,20 @@ function parseAttrs(str) {
76
76
  return attrs;
77
77
  }
78
78
 
79
+ /** 写入 props 定义条目(props 为定义数组,同名覆盖) */
80
+ function pushProp(node, name, type, value) {
81
+ if (!Array.isArray(node.props)) {
82
+ node.props = [];
83
+ }
84
+ const found = node.props.find((p) => p && p.name === name);
85
+ if (found) {
86
+ found.type = type;
87
+ found.value = value;
88
+ return;
89
+ }
90
+ node.props.push({ name, type, value });
91
+ }
92
+
79
93
  /** 属性列表 → 节点字段(attrs / props / directives / events / style) */
80
94
  function applyAttrs(node, attrs) {
81
95
  attrs.forEach((attr) => {
@@ -108,26 +122,24 @@ function applyAttrs(node, attrs) {
108
122
  return;
109
123
  }
110
124
  if (name.charAt(0) === ':') {
111
- node.props = node.props || {};
112
125
  const key = name.slice(1);
113
126
  const trimmed = String(value).trim();
114
- // 单引号且以 [ / { 开头:生成器的复杂值载体(紧凑 JSON),还原为真实数组/对象;
115
- // 双引号仍按表达式字符串处理,保持历史语义
127
+ // 单引号且以 [ / { 开头:生成器的复杂值载体(紧凑 JSON),还原为真实数组/对象
116
128
  if (attr.quote === "'" && /^[[{]/.test(trimmed)) {
117
129
  try {
118
- node.props[key] = new Function('return (' + trimmed + ');')();
130
+ pushProp(node, key, 'text', new Function('return (' + trimmed + ');')());
119
131
  } catch (e) {
120
- node.props[key] = String(value);
132
+ pushProp(node, key, 'text', String(value));
121
133
  }
122
134
  return;
123
135
  }
124
- // 数字/布尔直接还原类型,其它保留表达式字符串
136
+ // 数字/布尔直接还原类型;其它绑定表达式记为 {{var}} 变量引用
125
137
  if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
126
- node.props[key] = Number(trimmed);
138
+ pushProp(node, key, 'number', Number(trimmed));
127
139
  } else if (trimmed === 'true' || trimmed === 'false') {
128
- node.props[key] = trimmed === 'true';
140
+ pushProp(node, key, 'switch', trimmed === 'true');
129
141
  } else {
130
- node.props[key] = String(value);
142
+ pushProp(node, key, 'text', '{{' + trimmed + '}}');
131
143
  }
132
144
  return;
133
145
  }
@@ -153,7 +165,7 @@ export function migrateDirectives(node) {
153
165
  if (!node || typeof node !== 'object') {
154
166
  return node;
155
167
  }
156
- if (node.props) {
168
+ if (node.props && !Array.isArray(node.props)) {
157
169
  Object.keys(node.props).forEach((key) => {
158
170
  if (key.startsWith('v-')) {
159
171
  const dirKey = key.slice(2);
@@ -234,9 +246,51 @@ export function parseTemplateNodes(inner) {
234
246
  if (stack.length) {
235
247
  throw new Error('标签未正确闭合:<' + stack[stack.length - 1].name + '>');
236
248
  }
249
+ normalizeFormItems(roots);
237
250
  return roots;
238
251
  }
239
252
 
253
+ /**
254
+ * es-form-item 包裹结构 → 控件节点 + formItem 标记(genChildNode 的逆操作):
255
+ * JSON 不存包裹节点,label/prop 记在内层控件节点的 formItem 上,
256
+ * 画布由 form-render 渲染时重新生成包裹层;原地递归处理整棵节点树
257
+ * @param {Array} nodes 节点数组
258
+ * @returns {Array} 同一个节点数组
259
+ */
260
+ export function normalizeFormItems(nodes) {
261
+ nodes.forEach((node) => {
262
+ if (!node.children || !node.children.length) {
263
+ return;
264
+ }
265
+ node.children = node.children.map((child) => {
266
+ if (
267
+ child.name === 'es-form-item' &&
268
+ child.children &&
269
+ child.children.length === 1
270
+ ) {
271
+ const inner = child.children[0];
272
+ const meta = { ...(child.attrs || {}), ...(child.props || {}) };
273
+ inner.formItem = {
274
+ label: meta.label !== undefined ? String(meta.label) : '',
275
+ prop: meta.prop !== undefined ? String(meta.prop) : ''
276
+ };
277
+ // 包裹层宽度还原到控件节点 style.width(画布上作用于 es-form-item 根,
278
+ // 与 genChildNode 输出位置互逆)
279
+ if (child.style && child.style.width) {
280
+ inner.style = { ...(inner.style || {}), width: child.style.width };
281
+ }
282
+ if (!inner.description) {
283
+ inner.description = inner.formItem.label;
284
+ }
285
+ return inner;
286
+ }
287
+ return child;
288
+ });
289
+ normalizeFormItems(node.children);
290
+ });
291
+ return nodes;
292
+ }
293
+
240
294
  /** 给节点树回填 id(有 id 的保留,没有的按路径生成稳定 id) */
241
295
  let idSeed = 0;
242
296
  function assignIds(nodes) {
@@ -20,16 +20,19 @@
20
20
  : true
21
21
  "
22
22
  >
23
- <template v-if="newNode.children && newNode.children.length > 0">
24
- <Render
25
- v-for="(child, index) in newNode.children"
26
- :key="child.id"
27
- :node="child"
28
- :page="page"
29
- :drag="false"
30
- />
31
- </template>
32
- <template v-else>{{ resolvedText || newNode.description }}</template>
23
+ <!-- 不用 v-if/v-else 包裹:children 为空时假分支的空注释/文本节点
24
+ 会被 EsForm 等组件误判默认插槽有内容,导致 slot fallback 不渲染 -->
25
+ <!-- 子节点统一递归渲染;表单控件子节点(带 formItem 标记)复用
26
+ 编辑器同一个 form-render(es-form-item 包裹层渲染时生成,无选中手柄) -->
27
+ <component
28
+ :is="childRender(child)"
29
+ v-for="child in newNode.children"
30
+ :key="child.id"
31
+ :node="child"
32
+ :page="page"
33
+ :drag="false"
34
+ />
35
+ <template v-for="t in slotTexts">{{ t }}</template>
33
36
  </component>
34
37
  <template v-if="drag">
35
38
  <div class="es-lowcode__handles">
@@ -82,10 +85,13 @@
82
85
 
83
86
  <script>
84
87
  import Frame from './Iframe.vue';
88
+ import { propsToObject } from 'eoss/packages/lowcode/src/util/props-util.js';
89
+ import FormRender from 'eoss/packages/lowcode/src/form-render.vue';
85
90
  import EsButton from 'eoss/packages/button';
91
+
86
92
  export default {
87
93
  name: 'Render',
88
- components: { Frame, EsButton },
94
+ components: { Frame, FormRender, EsButton },
89
95
  props: {
90
96
  node: {
91
97
  type: Object,
@@ -206,6 +212,12 @@ export default {
206
212
  }
207
213
  return textExpr;
208
214
  },
215
+ /**
216
+ * 页面 data 变量:供 props 中 {{var}} 引用解析
217
+ */
218
+ pageData() {
219
+ return (this.page && this.page.data) || {};
220
+ },
209
221
  /**
210
222
  * 过滤掉 Vue 指令(v-xxx)的 props,避免它们作为普通属性传递给组件
211
223
  * 指令统一存在 directives 字段,这里仅兼容历史数据中混入 props 的 v- 键
@@ -217,19 +229,37 @@ export default {
217
229
  if (this.newNode.attrs) {
218
230
  Object.assign(result, this.newNode.attrs);
219
231
  }
220
- // 合并组件 props(跳过 Vue 指令)
221
- if (this.newNode.props) {
222
- Object.keys(this.newNode.props).forEach((key) => {
223
- if (key.startsWith('v-')) return;
224
- result[key] = this.newNode.props[key];
225
- });
226
- }
232
+ // 合并组件 props:定义数组经 propsToObject 转取值对象(含 {{var}} 解析)
233
+ Object.assign(result, propsToObject(this.newNode.props, this.pageData));
227
234
  return result;
235
+ },
236
+ /**
237
+ * 插槽文本:仅当无 children 时产出,
238
+ * 保证 EsForm 等组件在无字段时默认插槽为空、fallback 生效
239
+ */
240
+ slotTexts() {
241
+ const node = this.newNode;
242
+ if (!node) {
243
+ return [];
244
+ }
245
+ const hasChildren =
246
+ Array.isArray(node.children) && node.children.length > 0;
247
+ if (hasChildren) {
248
+ return [];
249
+ }
250
+ return [this.resolvedText || node.description || ''];
228
251
  }
229
252
  },
230
253
  mounted() {},
231
254
  beforeDestroy() {},
232
255
  methods: {
256
+ /**
257
+ * 子节点渲染器:表单控件子节点(带 formItem 标记)由 form-render 渲染,
258
+ * 其余走通用 Render(与编辑器 render.vue 同一判定)
259
+ */
260
+ childRender(child) {
261
+ return child && child.formItem ? 'FormRender' : 'Render';
262
+ },
233
263
  /**
234
264
  * 处理组件大小调整开始事件
235
265
  * @param event 指针事件对象
@@ -175,7 +175,6 @@ export default {
175
175
  message: '请输入新密码'
176
176
  }
177
177
  : {},
178
- ,
179
178
  {
180
179
  pattern: this.checkPassword,
181
180
  message: this.checkPasswordMsg
@@ -18,7 +18,7 @@
18
18
  :open-icon="openIcon"
19
19
  :close-icon="closeIcon"
20
20
  :isFourthTabs="isFourthTabs"
21
- :iconColor="getColor(index)"
21
+ :iconColor="getColor(index, item)"
22
22
  :iconColors="iconColors"
23
23
  ></component>
24
24
  </slot>
@@ -58,15 +58,19 @@ export default {
58
58
  if (!this._colorCache) {
59
59
  this._colorCache = {};
60
60
  }
61
- const isParentMenuIcon = item.children && item.children.length || (this.isFourthTabs && item.fourthTabs && item.fourthTabs.length);
62
- const key = Array.isArray(this.iconColors) ? `index_${index % this.iconColors.length}` : 'single_color';
61
+ // 缓存键为颜色槽位;缓存值仅依赖 iconColors 与槽位(iconColors 变化由 watcher 清缓存)
62
+ const key = Array.isArray(this.iconColors)
63
+ ? `index_${index % this.iconColors.length}`
64
+ : 'single_color';
63
65
 
64
66
  if (!this._colorCache[key]) {
65
- const bgColor = Array.isArray(this.iconColors) ? this.iconColors[index % this.iconColors.length] : this.iconColors;
67
+ const bgColor = Array.isArray(this.iconColors)
68
+ ? this.iconColors[index % this.iconColors.length]
69
+ : this.iconColors;
66
70
  this._colorCache[key] = {
67
71
  '--icon-bg-color': bgColor,
68
72
  '--icon-color': '#fff',
69
- '--icon-font-size': isParentMenuIcon ? '16px' : '12px'
73
+ '--icon-font-size': '12px'
70
74
  };
71
75
  }
72
76
 
@@ -151,7 +151,7 @@
151
151
  :close-icon="closeIcon"
152
152
  :isFourthTabs="isFourthTabs"
153
153
  :iconColors="iconColors"
154
- :iconColor="getColor(index)"
154
+ :iconColor="getColor(index, item)"
155
155
  >
156
156
  </component>
157
157
  </slot>
@@ -310,10 +310,10 @@ export default {
310
310
  return this.collapse ? 'es-zoom-in-left' : 'es-zoom-in-top';
311
311
  },
312
312
  opened() {
313
- const open =
314
- (this.open && !this.collapse) ||
315
- (this.index && this.rootMenu.openedMenus.indexOf(this.index) > -1);
316
- return open;
313
+ // 展开状态统一由 rootMenu.openedMenus 驱动,
314
+ // open 属性仅作为默认展开的初始值(见 syncOpenProp),不参与计算,
315
+ // 否则 open 为 true 时会短路导致点击无法折叠
316
+ return !!this.index && this.rootMenu.openedMenus.indexOf(this.index) > -1;
317
317
  },
318
318
  active() {
319
319
  let isActive = false;
@@ -417,6 +417,15 @@ export default {
417
417
  });
418
418
  }
419
419
  },
420
+ open() {
421
+ this.syncOpenProp();
422
+ },
423
+ collapse(val) {
424
+ // 整菜单收起会清空 openedMenus,取消收起后按 open 属性恢复默认展开
425
+ if (!val) {
426
+ this.syncOpenProp();
427
+ }
428
+ },
420
429
  iconColors() {
421
430
  // 当iconColors变化时,清除缓存
422
431
  this._colorCache = null;
@@ -456,6 +465,26 @@ export default {
456
465
  };
457
466
  },
458
467
  methods: {
468
+ /**
469
+ * 同步 open 属性到 rootMenu.openedMenus:
470
+ * open 语义为“默认展开”,写入 openedMenus 后仍可被点击正常折叠/展开
471
+ */
472
+ syncOpenProp() {
473
+ if (!this.index || this.collapse) {
474
+ return;
475
+ }
476
+ const rootMenu = this.rootMenu;
477
+ const isOpened = rootMenu.openedMenus.indexOf(this.index) > -1;
478
+ if (this.open && !isOpened) {
479
+ // 默认展开直接写入 openedMenus,不走 openMenu 的 uniqueOpened 过滤:
480
+ // 嵌套子菜单内层先于外层 mounted,若走 openMenu,
481
+ // 外层展开时会把不在其 indexPath 上的内层默认展开过滤收起
482
+ rootMenu.openedMenus.push(this.index);
483
+ rootMenu.$nextTick(() => rootMenu.updated());
484
+ } else if (!this.open && isOpened) {
485
+ rootMenu.closeMenu(this.index);
486
+ }
487
+ },
459
488
  handleCollapseToggle(value) {
460
489
  if (value) {
461
490
  this.initPopper();
@@ -567,6 +596,7 @@ export default {
567
596
  this.parentMenu.addSubmenu(this);
568
597
  this.rootMenu.addSubmenu(this);
569
598
  this.initPopper();
599
+ this.syncOpenProp();
570
600
  },
571
601
  updated() {
572
602
  this.$nextTick(() => {
@@ -65,7 +65,7 @@
65
65
  <script>
66
66
  import { getLoginCode } from 'eoss/src/config/api';
67
67
  import { ajax } from 'eoss/src/utils/ajax';
68
-
68
+ import { loading, error } from 'eoss/src/utils/util';
69
69
  import EsButton from 'eoss/packages/button';
70
70
  import EsForm from 'eoss/packages/form';
71
71
  import EsFormItem from 'eoss/packages/form-item';
@@ -274,6 +274,7 @@ export default {
274
274
  * 处理提交
275
275
  */
276
276
  handleSubmit() {
277
+ console.log('18086814030', this.$refs.loginForm);
277
278
  this.$refs.loginForm &&
278
279
  this.$refs.loginForm
279
280
  .validate()
@@ -305,7 +306,9 @@ export default {
305
306
  }
306
307
  this.$emit('submit', this.formData);
307
308
  })
308
- .catch(() => {});
309
+ .catch((e) => {
310
+ console.log('e', e);
311
+ });
309
312
  },
310
313
  /**
311
314
  * 处理键盘事件
@@ -188,6 +188,20 @@
188
188
  justify-content: flex-end;
189
189
  }
190
190
  }
191
+ @include e(props) {
192
+ color: #909399;
193
+ font-size: 12px;
194
+ line-height: 1.6;
195
+ @include m(tip) {
196
+ padding: 8px;
197
+ }
198
+
199
+ code {
200
+ padding: 0 2px;
201
+ color: #606266;
202
+ background: #f5f7fa;
203
+ }
204
+ }
191
205
  @include e(styles) {
192
206
  height: 100%;
193
207
  }
@@ -269,6 +283,7 @@
269
283
  }
270
284
  &::after {
271
285
  content: '';
286
+ display: block;
272
287
  position: absolute;
273
288
  top: 0;
274
289
  left: 0;
@@ -295,16 +310,20 @@
295
310
  }
296
311
  @include e(modules) {
297
312
  height: calc(100% - 32px);
298
- padding-right: 8px;
299
- padding-left: 8px;
300
313
  .es-collapse {
301
314
  border-top: none;
302
315
  }
316
+ .es-tabs__header {
317
+ padding: 0 12px;
318
+ }
303
319
  .es-tabs__nav-wrap {
304
320
  &::after {
305
321
  height: 1px;
306
322
  }
307
323
  }
324
+ .es-scrollbar__view {
325
+ padding: 8px;
326
+ }
308
327
  @include m(item) {
309
328
  display: flex;
310
329
  flex-direction: column;