@steedos-widgets/amis-lib 3.6.2-beta.8 → 3.6.2

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/dist/index.cjs.js CHANGED
@@ -362,27 +362,33 @@ const getSteedosAuth = () => {
362
362
  /*
363
363
  * @Author: baozhoutao@steedos.com
364
364
  * @Date: 2022-08-16 17:02:08
365
- * @LastEditors: baozhoutao@steedos.com
366
- * @LastEditTime: 2023-06-20 13:50:15
365
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
366
+ * @LastEditTime: 2024-02-02 10:15:00
367
367
  * @Description:
368
368
  */
369
369
 
370
-
371
370
  const Router = {
372
- getTabDisplayAs(tab_id){
371
+ getTabDisplayAs(tab_id, defaultEnableSplit){
373
372
  var urlSearch = new URLSearchParams(document.location.search);
374
373
  if(urlSearch.has('display')){
375
374
  return urlSearch.get('display')
376
375
  }
377
376
  const key = `tab_${tab_id}_display`;
378
377
  // const key = `page_display`;
379
- const value = localStorage.getItem(key);
380
- return value ? value : 'grid'
378
+ const value = sessionStorage.getItem(key);
379
+ let defaultDisplay = "grid";
380
+ if(defaultEnableSplit === true){
381
+ defaultDisplay = "split";
382
+ }
383
+ if(window.innerWidth <= 768){
384
+ return "grid";
385
+ }
386
+ return value ? value : defaultDisplay;
381
387
  },
382
388
 
383
389
  setTabDisplayAs(tab_id, displayAs){
384
390
  const key = `tab_${tab_id}_display`;
385
- localStorage.setItem(key, displayAs);
391
+ sessionStorage.setItem(key, displayAs);
386
392
  },
387
393
  getAppPath({formFactor, appId}){
388
394
  return `/app/${appId}`;
@@ -409,8 +415,8 @@ const Router = {
409
415
  /*
410
416
  * @Author: baozhoutao@steedos.com
411
417
  * @Date: 2022-07-20 16:29:22
412
- * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
413
- * @LastEditTime: 2023-12-28 14:59:08
418
+ * @LastEditors: liaodaxue
419
+ * @LastEditTime: 2024-01-25 14:44:17
414
420
  * @Description:
415
421
  */
416
422
 
@@ -482,6 +488,25 @@ function getComparableAmisVersion() {
482
488
  }
483
489
  }
484
490
 
491
+ /**
492
+ * 判断浏览器类型
493
+ * @returns 按需返回浏览器类型;
494
+ */
495
+ function getBowserType() {
496
+ const userAgent = navigator.userAgent;
497
+ if (userAgent.indexOf("Chrome")!== -1 && userAgent.indexOf("Safari") !== -1 && userAgent.indexOf("Edg") === -1) {
498
+ return "Chrome";
499
+ } else if (userAgent.indexOf("Firefox") !== -1) {
500
+ return "Firefox";
501
+ } else if (userAgent.indexOf("Safari") !== -1 && userAgent.indexOf("Chrome") === -1 && userAgent.indexOf("Edge") === -1) {
502
+ return "Safari";
503
+ } else if (userAgent.indexOf("Edg") !== -1) {
504
+ return "Edge";
505
+ } else {
506
+ return "Unknown browser"; // 其他浏览器...(可根据自己需要确定是否新增其他浏览器的判断)
507
+ }
508
+ }
509
+
485
510
  /*
486
511
  * @Author: baozhoutao@steedos.com
487
512
  * @Date: 2022-05-23 09:53:08
@@ -544,7 +569,7 @@ function getSelectMap(selectOptions){
544
569
  _$1.forEach(selectOptions,(option)=>{
545
570
  const optionValue = option.value + '';
546
571
  const optionColor = option.color + '';
547
- if(optionColor){
572
+ if(optionColor && optionColor != "undefined"){
548
573
  const background = optionColor.charAt(0) === '#' ? optionColor : '#'+optionColor;
549
574
  const color = getContrastColor(background);
550
575
  const optionColorStyle = 'background:'+background+';color:'+color+';line-height:1.5rem';
@@ -1160,7 +1185,31 @@ const getAmisFileReadonlySchema = (steedosField)=>{
1160
1185
  }
1161
1186
  }
1162
1187
  if(type === 'file'){
1163
- return {
1188
+ return window.Meteor?.isCordova ? {
1189
+ "type": "control",
1190
+ "body": {
1191
+ "type": "each",
1192
+ "name": "_display." + steedosField.name,
1193
+ "items": {
1194
+ "type": "tpl",
1195
+ "tpl": "${name}",
1196
+ "className": "antd-Button--link inline-block",
1197
+ "onEvent": {
1198
+ "click": {
1199
+ "actions": [
1200
+ {
1201
+ "script": `
1202
+ Steedos.cordovaDownload(encodeURI(event.data.url), event.data.name);
1203
+ `,
1204
+ "actionType": "custom"
1205
+ }
1206
+ ],
1207
+ "weight": 0
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ } : {
1164
1213
  type: amisFieldType,
1165
1214
  tpl: `
1166
1215
  <% let fileData = data._display.${steedosField.name}; if (fileData) { %>
@@ -1304,6 +1353,7 @@ var frontend_notifications$1 = "Notifications";
1304
1353
  var frontend_notifications_allread$1 = "Mark all as read";
1305
1354
  var frontend_notifications_allread_message$1 = "All marked as read";
1306
1355
  var frontend_profile$1 = "Profile";
1356
+ var switch_space$1 = "Switch Space";
1307
1357
  var frontend_about$1 = "About";
1308
1358
  var frontend_log_out$1 = "Log out";
1309
1359
  var frontend_listview_warning_start$1 = "The current ";
@@ -1391,6 +1441,7 @@ var en_us = {
1391
1441
  frontend_notifications_allread: frontend_notifications_allread$1,
1392
1442
  frontend_notifications_allread_message: frontend_notifications_allread_message$1,
1393
1443
  frontend_profile: frontend_profile$1,
1444
+ switch_space: switch_space$1,
1394
1445
  frontend_about: frontend_about$1,
1395
1446
  frontend_log_out: frontend_log_out$1,
1396
1447
  frontend_listview_warning_start: frontend_listview_warning_start$1,
@@ -1446,7 +1497,7 @@ var frontend_listview_control_delete_label = "删除";
1446
1497
  var frontend_listview_control_delete_confirm_text = "如果您删除此列表视图,该视图将为所有具备访问权限的用户永久删除。是否确定要删除?";
1447
1498
  var frontend_listview_control_delete_message_success = "删除成功";
1448
1499
  var frontend_listview_control_filters = "过滤设置";
1449
- var frontend_listview_control_filters_fields_extend = "条件组件1";
1500
+ var frontend_listview_control_filters_fields_extend = "条件组件";
1450
1501
  var frontend_listview_control_new_label = "新建";
1451
1502
  var frontend_listview_control_new_title = "新建 列表视图";
1452
1503
  var frontend_listview_control_new_message_success = "成功";
@@ -1480,6 +1531,7 @@ var frontend_notifications = "通知";
1480
1531
  var frontend_notifications_allread = "全部标记为已读";
1481
1532
  var frontend_notifications_allread_message = "已全部标记为已读";
1482
1533
  var frontend_profile = "个人资料";
1534
+ var switch_space = "切换工作区";
1483
1535
  var frontend_about = "关于";
1484
1536
  var frontend_log_out = "注销";
1485
1537
  var frontend_listview_warning_start = "当前";
@@ -1568,6 +1620,7 @@ var zh_cn = {
1568
1620
  frontend_notifications_allread: frontend_notifications_allread,
1569
1621
  frontend_notifications_allread_message: frontend_notifications_allread_message,
1570
1622
  frontend_profile: frontend_profile,
1623
+ switch_space: switch_space,
1571
1624
  frontend_about: frontend_about,
1572
1625
  frontend_log_out: frontend_log_out,
1573
1626
  frontend_listview_warning_start: frontend_listview_warning_start,
@@ -1622,7 +1675,7 @@ async function getQuickEditSchema(field, options){
1622
1675
  isAmisVersionforBatchEdit = window.Amis.version[0] >= 3 && window.Amis.version[2] >= 2;
1623
1676
  }
1624
1677
  const quickEditId = options.objectName + "_" + field.name + "_quickEdit";//定义快速编辑的表单id,用于setvalue传值
1625
- var quickEditSchema = { body: [], id: quickEditId };
1678
+ var quickEditSchema = { body: [], id: quickEditId, className: "steedos-table-quickEdit" };
1626
1679
  //select,avatar,image,file等组件无法行记录字段赋值,暂不支持批量编辑;
1627
1680
  if(field.type != 'avatar' && field.type != 'image' && field.type != 'file' && isAmisVersionforBatchEdit){
1628
1681
  const submitEvent = {
@@ -1881,7 +1934,8 @@ async function getQuickEditSchema(field, options){
1881
1934
  "failed": "失败了呢。。"
1882
1935
  }
1883
1936
  }
1884
- }
1937
+ },
1938
+ "expression": "${!recordPermissions.modifyAllRecords}"
1885
1939
  },
1886
1940
  {
1887
1941
  "actionType": "setValue",
@@ -1897,7 +1951,7 @@ async function getQuickEditSchema(field, options){
1897
1951
  "componentId": quickEditId,
1898
1952
  "args": {
1899
1953
  "value":{
1900
- "quickedit_record_permissions": "${event.data}"
1954
+ "quickedit_record_permissions": "${recordPermissions.modifyAllRecords ? {'allowEdit': true} : event.data}"
1901
1955
  }
1902
1956
  }
1903
1957
  }
@@ -1961,7 +2015,7 @@ async function getQuickEditSchema(field, options){
1961
2015
  `
1962
2016
  }
1963
2017
  },
1964
- "expression":"${event.data.value}"
2018
+ "expression":"${event.data.value && !recordPermissions.modifyAllRecords}"
1965
2019
  },
1966
2020
  {
1967
2021
  "actionType": "setValue",
@@ -1992,10 +2046,20 @@ async function getQuickEditSchema(field, options){
1992
2046
  "script": `
1993
2047
  const noPermission = event.data.noPermission;
1994
2048
  const crudComponent = event.context.scoped.getComponentById("${options.crudId}");
1995
- const selectedItems = crudComponent && crudComponent.props.store.selectedItems.concat();
2049
+ let selectedItems = crudComponent && crudComponent.props.store.selectedItems.concat();
1996
2050
  noPermission.forEach(function (item) {
1997
2051
  crudComponent && crudComponent.unSelectItem(_.find(selectedItems,{_id:item}));
2052
+ _.remove(selectedItems, (selected) => selected._id === item);
1998
2053
  })
2054
+ doAction({
2055
+ "componentId": "${quickEditId}",
2056
+ "actionType": "setValue",
2057
+ "args": {
2058
+ "value": {
2059
+ selectedItems
2060
+ }
2061
+ }
2062
+ });
1999
2063
  `
2000
2064
  },
2001
2065
  {
@@ -2056,7 +2120,7 @@ async function getQuickEditSchema(field, options){
2056
2120
  }
2057
2121
 
2058
2122
  function getFieldWidth(width){
2059
- const defaultWidth = "unset";//用于使table内的td标签下生成div,实现将快速编辑按钮固定在右侧的效果,并不是为了unset效果
2123
+ const defaultWidth = null;
2060
2124
  if(typeof width == 'string'){
2061
2125
  if(isNaN(width)){
2062
2126
  return width || defaultWidth;
@@ -2086,18 +2150,35 @@ async function getTableColumns(fields, options){
2086
2150
  //增加quickEdit属性,实现快速编辑
2087
2151
  const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
2088
2152
  let className = "";
2089
- if(field.wrap != true){
2153
+ const bowserType = getBowserType();
2154
+ if(bowserType === "Safari"){
2090
2155
  className += " whitespace-nowrap ";
2091
2156
  }else {
2092
- className += " break-words ";
2157
+ if(field.wrap != true){
2158
+ className += " whitespace-nowrap ";
2159
+ }else {
2160
+ className += " break-words ";
2161
+ }
2162
+ }
2163
+
2164
+ if (typeof field.amis?.className == "object") {
2165
+ className = {
2166
+ [className]: "true",
2167
+ ...field.amis.className
2168
+ };
2169
+ } else if (typeof field.amis?.className == "string") {
2170
+ className = `${className} ${field.amis.className} `;
2093
2171
  }
2172
+ let fieldAmis = ___namespace.clone(field.amis);
2173
+ delete fieldAmis?.className;
2174
+
2094
2175
  let columnItem;
2095
2176
  if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
2096
2177
  const previewFileScript = `
2097
2178
  var data = event.data;
2098
2179
  var file_name = data.versions ? data.name : "${field.label}";
2099
- var file_id = data._id;
2100
- SteedosUI.previewFile && SteedosUI.previewFile({file_name, file_id});
2180
+ var file_id = data.versions && data.versions[0] && data.versions[0]._id;
2181
+ window.previewFile && window.previewFile({file_name, file_id});
2101
2182
  `;
2102
2183
  columnItem = {
2103
2184
  "type": "button",
@@ -2122,11 +2203,11 @@ async function getTableColumns(fields, options){
2122
2203
  "expression": "!!!(window && window.nw && window.nw.require)"//浏览器上直接下载
2123
2204
  },
2124
2205
  {
2125
- "args": {},
2126
- "actionType": "custom",
2127
- "script": previewFileScript,
2128
- // "expression": "!!window?.nw?.require" //PC客户端预览附件
2129
- "expression": "!!!(window && window.nw && window.nw.require)"//PC客户端预览附件
2206
+ "args": {},
2207
+ "actionType": "custom",
2208
+ "script": previewFileScript,
2209
+ // "expression": "!!window?.nw?.require" //PC客户端预览附件
2210
+ "expression": "!!(window && window.nw && window.nw.require)"//PC客户端预览附件
2130
2211
  }
2131
2212
  ]
2132
2213
  }
@@ -2141,7 +2222,7 @@ async function getTableColumns(fields, options){
2141
2222
  toggled: field.toggled,
2142
2223
  static: true,
2143
2224
  className,
2144
- }, field.amis, {name: field.name});
2225
+ }, fieldAmis, {name: field.name});
2145
2226
  }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
2146
2227
  columnItem = Object.assign({}, {
2147
2228
  type: "switch",
@@ -2152,7 +2233,7 @@ async function getTableColumns(fields, options){
2152
2233
  static: true,
2153
2234
  className,
2154
2235
  ...getAmisFileReadonlySchema(field)
2155
- }, field.amis, {name: field.name});
2236
+ }, fieldAmis, {name: field.name});
2156
2237
  }
2157
2238
  else if(field.type === 'select'){
2158
2239
  const map = getSelectMap(field.options);
@@ -2167,7 +2248,7 @@ async function getTableColumns(fields, options){
2167
2248
  className,
2168
2249
  inputClassName: "inline",
2169
2250
  static: true,
2170
- }, field.amis, {name: field.name});
2251
+ }, fieldAmis, {name: field.name});
2171
2252
  }
2172
2253
  else {
2173
2254
  const tpl = await getFieldTpl(field, options);
@@ -2186,23 +2267,14 @@ async function getTableColumns(fields, options){
2186
2267
  if(field.type === 'textarea'){
2187
2268
  className += 'min-w-56';
2188
2269
  }
2189
- if(field.type === 'date'){
2190
- className += 'date-min-w';
2191
- }
2192
- if(field.type === 'datetime'){
2193
- className += 'datetime-min-w';
2194
- }
2270
+ // if(field.type === 'date'){
2271
+ // className += 'date-min-w';
2272
+ // }
2273
+ // if(field.type === 'datetime'){
2274
+ // className += 'datetime-min-w';
2275
+ // }
2195
2276
 
2196
2277
  //field上的amis属性里的clssname需要单独判断类型合并
2197
- if (typeof field.amis?.className == "object") {
2198
- className = {
2199
- [className]: "true",
2200
- ...field.amis.className
2201
- };
2202
- } else if (typeof field.amis?.className == "string") {
2203
- className = `${className} ${field.amis.className} `;
2204
- }
2205
- delete field.amis?.className;
2206
2278
 
2207
2279
  if(!field.hidden && !field.extra){
2208
2280
  columnItem = Object.assign({}, {
@@ -2219,7 +2291,7 @@ async function getTableColumns(fields, options){
2219
2291
  static: true,
2220
2292
  options: field.type === 'html' ? {html: true} : null
2221
2293
  // toggled: true
2222
- }, field.amis, {name: field.name});
2294
+ }, fieldAmis, {name: field.name});
2223
2295
 
2224
2296
  if(field.type === 'color'){
2225
2297
  columnItem.type = 'color';
@@ -2415,10 +2487,10 @@ async function getMobileTableColumns(fields, options){
2415
2487
  if(value.url){
2416
2488
  cms_url = value.url;
2417
2489
  }else{
2418
- cms_url = "/api/files/files/"+value+"?download=true"
2490
+ cms_url = Steedos.absoluteUrl("/api/files/files/"+value+"?download=true");
2419
2491
  }
2420
2492
  }
2421
- Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
2493
+ Steedos.cordovaDownload(encodeURI(cms_url), event.data.name);
2422
2494
  `,
2423
2495
  "actionType": "custom"
2424
2496
  }
@@ -2918,6 +2990,21 @@ async function getTableApi(mainObject, fields, options){
2918
2990
  return api;
2919
2991
  `;
2920
2992
  api.adaptor = `
2993
+ let fields = ${JSON.stringify(___namespace.map(fields, 'name'))};
2994
+ // 这里把行数据中所有为空的字段值配置为空字符串,是因为amis有bug:crud的columns中的列如果type为static-前缀的话,行数据中该字段为空的话会显示为父作用域中同名变量值,见:https://github.com/baidu/amis/issues/9556
2995
+ (payload.data.rows || []).forEach((itemRow) => {
2996
+ (fields || []).forEach((itemField) => {
2997
+ if(itemField && itemField.indexOf(".") > -1){
2998
+ return;
2999
+ }
3000
+ if(itemField && (itemRow[itemField] === undefined || itemRow[itemField] === null)){
3001
+ // 这里itemRow中不存在 itemField 属性,或者值为null时都会有“显示为父作用域中的同名变量值”的问题,所以null和undefined都要重置为空字符串
3002
+ // 实测数字、下拉框、多选lookup等字段类型重置为空字符串都不会有问题,而且实测amis from组件的清空表单字段值功能就是把表单中的各种字段类型设置为空字符串,所以看起来也符合amis规范
3003
+ itemRow[itemField] = "";
3004
+ }
3005
+ });
3006
+ });
3007
+
2921
3008
  if(api.body.listName == "recent"){
2922
3009
  payload.data.rows = _.sortBy(payload.data.rows, function(item){
2923
3010
  return _.indexOf(api.body._ids, item._id)
@@ -2942,7 +3029,13 @@ async function getTableApi(mainObject, fields, options){
2942
3029
  value = [value]
2943
3030
  };
2944
3031
  if(field.type === 'file'){
2945
- item[key] = value
3032
+ // item[key] = value
3033
+ // PC客户端附件子表列表点击标题预览附件功能依赖了_id,所以这里拼出来
3034
+ let itemKeyValue = item[key];
3035
+ item[key] = value.map(function(item, index){
3036
+ item._id = itemKeyValue[index];
3037
+ return item;
3038
+ });
2946
3039
  }else{
2947
3040
  item[key] = _.map(value, (item)=>{
2948
3041
  if(field.type === 'image'){
@@ -2984,15 +3077,8 @@ async function getTableApi(mainObject, fields, options){
2984
3077
  }
2985
3078
  });
2986
3079
  };
2987
- let isTreeOptionsComputed = false;
2988
- if(records.length === 1 && records[0].children){
2989
- isTreeOptionsComputed = true;
2990
- }
2991
- if(!isTreeOptionsComputed){
2992
- // 如果api接口设置在缓存,缓存期间并不会重新请求接口,payload.data.rows是上次计算后的结果
2993
- payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
2994
- assignIndexToTreeRecords(payload.data.rows, '');
2995
- }
3080
+ payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
3081
+ assignIndexToTreeRecords(payload.data.rows, '');
2996
3082
  }
2997
3083
 
2998
3084
 
@@ -3051,11 +3137,10 @@ async function getTableApi(mainObject, fields, options){
3051
3137
  };
3052
3138
  let formFactor = "${options.formFactor}";
3053
3139
  if(formFactor !== "SMALL"){
3054
- const listviewComponent = $(".steedos-object-listview .antd-Table-table");
3055
- const firstListviewComponent = listviewComponent && listviewComponent[0];
3056
- if(firstListviewComponent){
3140
+ const lisviewDom = document.querySelector(".steedos-object-listview .antd-Table-table");
3141
+ if(lisviewDom){
3057
3142
  setTimeout(()=>{
3058
- firstListviewComponent.scrollIntoView();
3143
+ lisviewDom.scrollIntoView();
3059
3144
  }, 600);
3060
3145
  }
3061
3146
  }
@@ -4888,9 +4973,16 @@ const getSchema$2 = (uiSchema) => {
4888
4973
  "form": {
4889
4974
  debug: false,
4890
4975
  resetAfterSubmit: false,
4976
+ data: {
4977
+ editFormInited: true,
4978
+ },
4891
4979
  initApi: {
4980
+ method: 'GET',
4892
4981
  url: '/api/v1/queue_import_history/${recordId}?fields=["state"]',
4893
4982
  sendOn: 'this.recordId',
4983
+ data: null,
4984
+ requestAdaptor: "return api;",
4985
+ adaptor: "return payload;",
4894
4986
  responseData: {
4895
4987
  importState: "${state}"
4896
4988
  }
@@ -5762,7 +5854,7 @@ async function getObjectFieldsFilterFormSchema(ctx) {
5762
5854
  const formSchema = {
5763
5855
  "type": "service",
5764
5856
  "visibleOn": "this.filterFormSearchableFields && this.filterFormSearchableFields.length",
5765
- "className": ctx.formFactor === 'SMALL' ? "slds-filters__body p-0 mb-2 overflow-y-auto overflow-x-hidden" : "slds-filters__body p-0 sm:grid sm:gap-2 sm:grid-cols-4 mb-2",
5857
+ "className": ctx.formFactor === 'SMALL' ? "slds-filters__body p-0 mb-2 overflow-y-auto overflow-x-hidden" : "slds-filters__body p-0 sm:grid sm:gap-4 sm:grid-cols-4 p-2",
5766
5858
  "style":{
5767
5859
  "max-height":ctx.formFactor === 'SMALL'?"30vh":"unset"
5768
5860
  },
@@ -6349,7 +6441,7 @@ async function getObjectFieldsFilterBarSchema(objectSchema, ctx) {
6349
6441
  "className": "slds-filters"
6350
6442
  },
6351
6443
  "size": "xs",
6352
- "className": `border-gray-300 border-y slds-grid slds-grid_vertical slds-nowrap ${!ctx.isLookup && "mt-2"}`,
6444
+ "className": `border-y slds-grid slds-grid_vertical slds-nowrap ${!ctx.isLookup && "mt-2"}`,
6353
6445
  "visibleOn": "this.showFieldsFilter",
6354
6446
  },
6355
6447
  "className": "bg-white"
@@ -6537,7 +6629,7 @@ async function getObjectListHeaderSecordLine(objectSchema, listViewName, ctx) {
6537
6629
  "icon": "fa fa-refresh",
6538
6630
  "actionType": "reload",
6539
6631
  "target": amisListViewId,
6540
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
6632
+ "className": "bg-white p-2 rounded text-gray-500"
6541
6633
  },
6542
6634
  fieldsFilterButtonSchema,
6543
6635
  // {
@@ -6545,7 +6637,7 @@ async function getObjectListHeaderSecordLine(objectSchema, listViewName, ctx) {
6545
6637
  // "label": "",
6546
6638
  // "icon": "fa fa-filter",
6547
6639
  // "actionType": "custom",
6548
- // "className": "bg-transparent p-2 rounded border-gray-300 text-gray-500",
6640
+ // "className": "bg-transparent p-2 rounded text-gray-500",
6549
6641
  // "id": "u:c20cb87d96c9",
6550
6642
  // "onEvent": {
6551
6643
  // "click": {
@@ -6593,7 +6685,7 @@ function getObjectListHeader$1(objectSchema, listViewName, ctx) {
6593
6685
  let headerSchema = [{
6594
6686
  "type": "wrapper",
6595
6687
  "body": body,
6596
- "className": `bg-gray-100 sm:rounded-tl sm:rounded-tr p-4 -mb-4`
6688
+ "className": `sm:rounded-tl sm:rounded-tr p-4 -mb-4`
6597
6689
  }];
6598
6690
  return headerSchema;
6599
6691
  }
@@ -6728,7 +6820,7 @@ async function getObjectRecordDetailHeader(objectSchema, recordId, options) {
6728
6820
  let body = [
6729
6821
  {
6730
6822
  "type": "wrapper",
6731
- "className": "p-4 bg-gray-100 border-b",
6823
+ "className": "p-4 border-b",
6732
6824
  "body": [
6733
6825
  {
6734
6826
  "type": "grid",
@@ -6758,8 +6850,27 @@ async function getObjectRecordDetailHeader(objectSchema, recordId, options) {
6758
6850
  let max = 10;
6759
6851
  if(options.formFactor === 'SMALL'){
6760
6852
  max = 4;
6853
+ }else {
6854
+
6855
+ let divWidth = window.innerWidth;
6856
+
6857
+ if(options.display === 'split'){
6858
+ divWidth = divWidth - 388;
6859
+ }
6860
+
6861
+ if(document.body.classList.contains('sidebar')){
6862
+ divWidth = divWidth - 210;
6863
+ }
6864
+
6865
+ // 根据屏幕宽度计算显示数量, 使高亮字段只占1行
6866
+ max = Math.trunc(divWidth / 200 );
6867
+ if(max > 10){
6868
+ max = 10;
6869
+ }
6761
6870
  }
6762
6871
 
6872
+ // console.log('=======================max=========================', max)
6873
+
6763
6874
  if(objectSchema.compactLayouts){
6764
6875
  const details = [];
6765
6876
  _.each(_.slice(_.difference(objectSchema.compactLayouts, [objectSchema.NAME_FIELD_KEY]), 0, max), (fieldName)=>{
@@ -6773,11 +6884,26 @@ async function getObjectRecordDetailHeader(objectSchema, recordId, options) {
6773
6884
  }
6774
6885
  });
6775
6886
 
6887
+ // 注意: 以下注释不能删除. tailwind css 动态编译时会识别以下注释, 生成对应的样式
6888
+ // lg:grid-cols-1
6889
+ // lg:grid-cols-2
6890
+ // lg:grid-cols-3
6891
+ // lg:grid-cols-4
6892
+ // lg:grid-cols-5
6893
+ // lg:grid-cols-6
6894
+ // lg:grid-cols-7
6895
+ // lg:grid-cols-8
6896
+ // lg:grid-cols-9
6897
+ // lg:grid-cols-10
6898
+ // lg:grid-cols-11
6899
+ // lg:grid-cols-12
6900
+
6776
6901
  body.push({
6777
6902
  "type": "wrapper",
6778
6903
  "body": {
6779
6904
  "type": "form",
6780
- "className": "gap-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-5 3xl:grid-cols-8 4xl:grid-cols-8 5xl:grid-cols-10", //max-h-12 overflow-hidden
6905
+ // "className": "gap-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-5 3xl:grid-cols-8 4xl:grid-cols-8 5xl:grid-cols-10", //max-h-12 overflow-hidden
6906
+ "className": `gap-2 grid grid-cols-1 lg:grid-cols-${max}`,
6781
6907
  "wrapWithPanel": false,
6782
6908
  "actions": [],
6783
6909
  "body": details,
@@ -6862,7 +6988,7 @@ async function getObjectRecordDetailRelatedListHeader(relatedObjectSchema, relat
6862
6988
  "className": "flex justify-between"
6863
6989
  }
6864
6990
  ],
6865
- "className": "steedos-record-related-header py-2 px-0"
6991
+ "className": "steedos-record-related-header py-2 px-3 bg-gray-50 border"
6866
6992
  };
6867
6993
  return recordRelatedListHeader;
6868
6994
  }
@@ -6905,6 +7031,7 @@ const getNewListviewButtonSchema = ()=>{
6905
7031
  "objectApiName": "object_listviews",
6906
7032
  "recordId": "",
6907
7033
  "mode": "edit",
7034
+ "layout": "normal",
6908
7035
  "defaultData": {
6909
7036
  "&": "${list_view}",
6910
7037
  "name":"",
@@ -6912,8 +7039,16 @@ const getNewListviewButtonSchema = ()=>{
6912
7039
  "filters":"",
6913
7040
  "shared":false,
6914
7041
  "object_name": "${targetObjectName}",
7042
+ "_id":"",
7043
+ "shared_to": null,
7044
+ "shared_to_organizations": null,
7045
+ "locked": false,
7046
+ "owner": null,
7047
+ "company_id": null,
7048
+ "company_ids": null,
7049
+ "is_system": false
6915
7050
  },
6916
- "fieldsExtend": fieldsExtend$4(),
7051
+ "fieldsExtend": fieldsExtend$5(),
6917
7052
  "fields": fields$1(),
6918
7053
  "onEvent": {
6919
7054
  "submitSucc": {
@@ -6964,14 +7099,17 @@ function fields$1(){
6964
7099
  "mobile_columns",
6965
7100
  "searchable_fields",
6966
7101
  "is_system",
6967
- "shared"
7102
+ "shared",
7103
+ "shared_to",
7104
+ "shared_to_organizations"
6968
7105
  ]
6969
7106
  }
6970
7107
 
6971
- function fieldsExtend$4(){
7108
+ function fieldsExtend$5(){
6972
7109
  return {
6973
7110
  "group": "",
6974
7111
  "label": {
7112
+ "group": "",
6975
7113
  "is_wide": true
6976
7114
  },
6977
7115
  "name": {
@@ -7053,9 +7191,19 @@ function fieldsExtend$4(){
7053
7191
  "shared": {
7054
7192
  "group": "",
7055
7193
  "amis": {
7056
- "visibleOn": "${global.user.is_space_admin}"
7194
+ "visibleOn": "${false}"
7195
+ }
7196
+ },
7197
+ "shared_to": {
7198
+ "group": "",
7199
+ "amis":{
7200
+ "type": "radios",
7201
+ "inline": false
7057
7202
  }
7058
7203
  },
7204
+ "shared_to_organizations": {
7205
+ "group": ""
7206
+ },
7059
7207
  "filters": {
7060
7208
  "group": "",
7061
7209
  "amis": {
@@ -7093,14 +7241,23 @@ const getCopyListviewButtonSchema = ()=>{
7093
7241
  "objectApiName": "object_listviews",
7094
7242
  "recordId": "",
7095
7243
  "mode": "edit",
7244
+ "layout": "normal",
7096
7245
  "defaultData": {
7097
7246
  "&": "${list_view}",
7098
7247
  "name":"",
7099
7248
  "label": i18next__default["default"].t('frontend_listview_control_clone_defaultData_label_start') + " ${list_view.label} " + i18next__default["default"].t('frontend_listview_control_clone_defaultData_label_end'),
7100
7249
  "shared":false,
7101
7250
  "object_name": "${targetObjectName}",
7251
+ "_id":"",
7252
+ "shared_to": null,
7253
+ "shared_to_organizations": null,
7254
+ "locked": false,
7255
+ "owner": null,
7256
+ "company_id": null,
7257
+ "company_ids": null,
7258
+ "is_system": false
7102
7259
  },
7103
- "fieldsExtend": fieldsExtend$3(),
7260
+ "fieldsExtend": fieldsExtend$4(),
7104
7261
  "fields": fields(),
7105
7262
  "onEvent": {
7106
7263
  "submitSucc": {
@@ -7148,13 +7305,16 @@ function fields(){
7148
7305
  "mobile_columns.$.field",
7149
7306
  "searchable_fields.$.field",
7150
7307
  "is_system",
7151
- "shared"
7308
+ "shared",
7309
+ "shared_to",
7310
+ "shared_to_organizations"
7152
7311
  ]
7153
7312
  }
7154
7313
 
7155
- function fieldsExtend$3(){
7314
+ function fieldsExtend$4(){
7156
7315
  return {
7157
7316
  "label": {
7317
+ "group": "",
7158
7318
  "is_wide": true
7159
7319
  },
7160
7320
  "name": {
@@ -7204,10 +7364,21 @@ function fieldsExtend$3(){
7204
7364
  }
7205
7365
  },
7206
7366
  "shared": {
7367
+ "group": "",
7207
7368
  "amis": {
7208
- "visibleOn": "${global.user.is_space_admin}"
7369
+ "visibleOn": "${false}"
7370
+ }
7371
+ },
7372
+ "shared_to": {
7373
+ "group": "",
7374
+ "amis":{
7375
+ "type": "radios",
7376
+ "inline": false
7209
7377
  }
7210
7378
  },
7379
+ "shared_to_organizations": {
7380
+ "group": ""
7381
+ },
7211
7382
  "filters": {
7212
7383
  "group": "",
7213
7384
  "amis": {
@@ -7217,6 +7388,12 @@ function fieldsExtend$3(){
7217
7388
  }
7218
7389
  }
7219
7390
 
7391
+ /*
7392
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
7393
+ * @Date: 2023-06-13 13:51:19
7394
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
7395
+ * @LastEditTime: 2024-02-05 11:25:09
7396
+ */
7220
7397
  const getRenameListviewButtonSchema = ()=>{
7221
7398
  return {
7222
7399
  "type": "button",
@@ -7242,6 +7419,7 @@ const getRenameListviewButtonSchema = ()=>{
7242
7419
  "label": "对象表单",
7243
7420
  "objectApiName": "object_listviews",
7244
7421
  "recordId": "${recordId}",
7422
+ "layout": "normal",
7245
7423
  "mode": "edit",
7246
7424
  "fields": [
7247
7425
  "label"
@@ -7276,6 +7454,12 @@ const getRenameListviewButtonSchema = ()=>{
7276
7454
  }
7277
7455
  };
7278
7456
 
7457
+ /*
7458
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
7459
+ * @Date: 2023-06-13 13:51:19
7460
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
7461
+ * @LastEditTime: 2024-02-06 15:38:49
7462
+ */
7279
7463
  const getSetListviewShareButtonSchema = ()=>{
7280
7464
  return {
7281
7465
  "type": "button",
@@ -7291,6 +7475,8 @@ const getSetListviewShareButtonSchema = ()=>{
7291
7475
  "title": i18next__default["default"].t('frontend_listview_control_share'),
7292
7476
  "data": {
7293
7477
  "recordId": "${uiSchema.list_views[listName]._id}",
7478
+ "appId": "${appId}",
7479
+ "global": "${global}",
7294
7480
  "context": "${context}"
7295
7481
  },
7296
7482
  "body": [
@@ -7300,9 +7486,12 @@ const getSetListviewShareButtonSchema = ()=>{
7300
7486
  "objectApiName": "object_listviews",
7301
7487
  "recordId": "${recordId}",
7302
7488
  "mode": "edit",
7489
+ "layout": "normal",
7303
7490
  "fields": [
7304
- "shared"
7305
- ]
7491
+ "shared_to",
7492
+ "shared_to_organizations"
7493
+ ],
7494
+ "fieldsExtend": fieldsExtend$3(),
7306
7495
  }
7307
7496
  ],
7308
7497
  "showCloseButton": true,
@@ -7320,6 +7509,21 @@ const getSetListviewShareButtonSchema = ()=>{
7320
7509
  }
7321
7510
  };
7322
7511
 
7512
+ function fieldsExtend$3(){
7513
+ return {
7514
+ "shared_to": {
7515
+ "group": "",
7516
+ "amis":{
7517
+ "type": "radios",
7518
+ "inline": false
7519
+ }
7520
+ },
7521
+ "shared_to_organizations": {
7522
+ "group": ""
7523
+ }
7524
+ }
7525
+ }
7526
+
7323
7527
  const getSetListviewFiltersButtonSchema = ()=>{
7324
7528
  return {
7325
7529
  "type": "button",
@@ -7451,10 +7655,12 @@ function apiRequestAdaptor$2(){
7451
7655
  function fieldsExtend$2(){
7452
7656
  return {
7453
7657
  "filters": {
7658
+ "label": "",
7659
+ "group": "",
7454
7660
  "visible_on": "true",
7455
7661
  "amis": {
7456
7662
  "type": "condition-builder",
7457
- "label": i18next__default["default"].t('frontend_listview_control_filters_fields_extend'),
7663
+ // "label": i18next.t('frontend_listview_control_filters_fields_extend'),
7458
7664
  "source": {
7459
7665
  "method": "get",
7460
7666
  "url": "${context.rootUrl}/service/api/amis-metadata-listviews/getFilterFields?objectName=${targetObjectName}",
@@ -7497,6 +7703,7 @@ const getSetListviewColumnsButtonSchema = ()=>{
7497
7703
  "objectApiName": "object_listviews",
7498
7704
  "recordId": "${recordId}",
7499
7705
  "mode": "edit",
7706
+ "layout": "normal",
7500
7707
  "fieldsExtend": fieldsExtend$1(),
7501
7708
  "initApiAdaptor": initApiAdaptor$1(),
7502
7709
  "apiRequestAdaptor": apiRequestAdaptor$1(),
@@ -7693,6 +7900,8 @@ const getSetListviewSortButtonSchema = ()=>{
7693
7900
  function fieldsExtend(){
7694
7901
  return {
7695
7902
  "sort": {
7903
+ "label": "",
7904
+ "group": "",
7696
7905
  "amis": {
7697
7906
  "type": "tabs-transfer",
7698
7907
  "sortable": true,
@@ -7820,7 +8029,7 @@ const getSettingListviewToolbarButtonSchema = ()=>{
7820
8029
  "icon": "fa fa-cog",
7821
8030
  //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,为保持统一,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
7822
8031
  // "tooltip": i18next.t('frontend_button_listview_control_tooltip'),
7823
- "btnClassName": "antd-Button--iconOnly bg-white !p-2 rounded border-gray-300 text-gray-500",
8032
+ "btnClassName": "antd-Button--iconOnly bg-white !p-2 rounded text-gray-500",
7824
8033
  "align": "right",
7825
8034
  "visibleOn": "${!isLookup}",
7826
8035
  "buttons": [
@@ -7841,20 +8050,20 @@ const getSettingListviewToolbarButtonSchema = ()=>{
7841
8050
  }
7842
8051
  };
7843
8052
 
7844
- const getDisplayAsButton = function(objectName, showDisplayAs){
7845
- let displayAs = amisLib.Router.getTabDisplayAs(objectName);
8053
+ const getDisplayAsButton = function(objectName, defaultEnableSplit){
8054
+ let displayAs = amisLib.Router.getTabDisplayAs(objectName, defaultEnableSplit);
7846
8055
  let buttons = [
7847
8056
  {
7848
8057
  "type": "button",
7849
8058
  "label": i18next__default["default"].t('frontend_display_type_is_table'),
7850
- "onClick": "const key = 'tab_"+objectName+"_display';localStorage.setItem(key, 'grid');let url = document.location.pathname; var urlSearch = new URLSearchParams(document.location.search); if(urlSearch.get(\"side_object\") && urlSearch.get(\"side_listview_id\")){url=`/app/${props.data.appId}/${urlSearch.get(\"side_object\")}/grid/${urlSearch.get(\"side_listview_id\")}`;}; props.env.jumpTo(url + '?display=grid');",
8059
+ "onClick": "const key = 'tab_"+objectName+"_display';sessionStorage.setItem(key, 'grid');let url = document.location.pathname; var urlSearch = new URLSearchParams(document.location.search); if(urlSearch.get(\"side_object\") && urlSearch.get(\"side_listview_id\")){url=`/app/${props.data.appId}/${urlSearch.get(\"side_object\")}/grid/${urlSearch.get(\"side_listview_id\")}`;}; props.env.jumpTo(url + '?display=grid');",
7851
8060
  "rightIcon": displayAs != 'split' ? "fa fa-check" : null,
7852
8061
  "rightIconClassName": "m-l-sm"
7853
8062
  },
7854
8063
  {
7855
8064
  "type": "button",
7856
8065
  "label": i18next__default["default"].t('frontend_display_type_is_split'),
7857
- "onClick": "const key = 'tab_"+objectName+"_display';localStorage.setItem(key, 'split');const url = document.location.pathname + '?display=split'; props.env.jumpTo(url);",
8066
+ "onClick": "const key = 'tab_"+objectName+"_display';sessionStorage.setItem(key, 'split');const url = document.location.pathname + '?display=split'; props.env.jumpTo(url);",
7858
8067
  "rightIcon": displayAs === 'split' ? "fa fa-check" : null,
7859
8068
  "rightIconClassName": "m-l-sm"
7860
8069
  }
@@ -7865,7 +8074,7 @@ const getDisplayAsButton = function(objectName, showDisplayAs){
7865
8074
  "icon": "fa fa-table-columns",
7866
8075
  //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
7867
8076
  // "tooltip": `${i18next.t('frontend_display_as')} ${displayAsLabel}`,
7868
- "btnClassName": "antd-Button--iconOnly bg-white !p-2 rounded border-gray-300 text-gray-500",
8077
+ "btnClassName": "antd-Button--iconOnly bg-white !p-2 rounded text-gray-500",
7869
8078
  "align": "right",
7870
8079
  "visibleOn": "${window:innerWidth > 768 && !!!isLookup}",
7871
8080
  "buttons": [
@@ -8058,7 +8267,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8058
8267
  // //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,为保持统一,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
8059
8268
  // // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8060
8269
  // "tooltipPlacement": "top",
8061
- // "className": "bg-white p-2 rounded border-gray-300 text-gray-500",
8270
+ // "className": "bg-white p-2 rounded text-gray-500",
8062
8271
  // "label": "",
8063
8272
  // "icon": "fa fa-sync",
8064
8273
  // "visibleOn": "${!showFieldsFilter}",
@@ -8082,7 +8291,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8082
8291
  // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8083
8292
  "tooltip":"",
8084
8293
  "tooltipPlacement": "top",
8085
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
8294
+ "className": "bg-white p-2 rounded text-gray-500"
8086
8295
  };
8087
8296
  }
8088
8297
  else {
@@ -8093,7 +8302,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8093
8302
  // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8094
8303
  "tooltip":"",
8095
8304
  "tooltipPlacement": "top",
8096
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
8305
+ "className": "bg-white p-2 rounded text-gray-500"
8097
8306
  };
8098
8307
  }
8099
8308
  let toolbarFilter;
@@ -8115,7 +8324,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8115
8324
  "visibleOn": "${isFieldsFilterEmpty == false && isLookup != true}"
8116
8325
  },
8117
8326
  "align": "right",
8118
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500",
8327
+ "className": "bg-white p-2 rounded text-gray-500",
8119
8328
  "onEvent": {
8120
8329
  "click": {
8121
8330
  "actions": [
@@ -8129,7 +8338,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8129
8338
  "id": "steedos_crud_toolbar_filter"
8130
8339
  };
8131
8340
  }
8132
- let toolbarDisplayAsButton = getDisplayAsButton(mainObject?.name);
8341
+ let toolbarDisplayAsButton = getDisplayAsButton(mainObject?.name, mainObject?.enable_split);
8133
8342
  let toolbarDQuickSearchBox = getObjectHeaderQuickSearchBox(mainObject, fields, formFactor, { isLookup, keywordsSearchBoxName });
8134
8343
 
8135
8344
  // toolbars返回的数组元素不可以是空对象{},比如hiddenCount ? {} : {"type": "tpl",...},因为空对象最终还是会生成一个空的.antd-Crud-toolbar-item dom
@@ -8275,7 +8484,6 @@ async function getObjectFilter(objectSchema, fields, options) {
8275
8484
  "timeOut": 1000
8276
8485
  }
8277
8486
  });
8278
- resizeWindow();
8279
8487
  const scope = event.context.scoped;
8280
8488
  // let filterFormValues = event.data;
8281
8489
  let filterForm = SteedosUI.getClosestAmisComponentByType(scope, "form");
@@ -8442,7 +8650,7 @@ async function getObjectCRUD(objectSchema, fields, options){
8442
8650
  const bodyProps = {
8443
8651
  // toolbar: getToolbar(),
8444
8652
  // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
8445
- headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
8653
+ headerToolbarClassName: "px-4 py-2 border-b",
8446
8654
  footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
8447
8655
  ...options,
8448
8656
  disableStatistics: options.queryCount === false
@@ -8589,14 +8797,7 @@ async function getObjectCRUD(objectSchema, fields, options){
8589
8797
  headers: {
8590
8798
  Authorization: "Bearer ${context.tenantId},${context.authToken}",
8591
8799
  },
8592
- requestAdaptor: quickSaveApiRequestAdaptor,
8593
- adaptor: `
8594
- if(payload.errors){
8595
- payload.status = 2;
8596
- payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
8597
- }
8598
- return payload;
8599
- `
8800
+ requestAdaptor: quickSaveApiRequestAdaptor
8600
8801
  },
8601
8802
  // 外层data发生变化的时候, 不会重新渲染rowClassNameExpr, 所以先用css标记tr唯一标识
8602
8803
  // 使用表达式给tr添加初始选中状态
@@ -8613,6 +8814,20 @@ async function getObjectCRUD(objectSchema, fields, options){
8613
8814
  crudModeClassName = `steedos-crud-mode-${body.mode}`;
8614
8815
  }
8615
8816
 
8817
+ body.quickSaveApi.adaptor = `
8818
+ if(payload.errors){
8819
+ payload.status = 2;
8820
+ payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
8821
+ }
8822
+ var scope = SteedosUI.getRef(context.scopeId);
8823
+ var scopeParent = scope && scope.parent;
8824
+ var crudScoped = scopeParent.getComponentById('${body.id}');
8825
+ setTimeout(()=>{
8826
+ crudScoped && crudScoped.control.updateAutoFillHeight();
8827
+ }, 500);
8828
+ return payload;
8829
+ `;
8830
+
8616
8831
  if(body.columns && options.formFactor != 'SMALL'){
8617
8832
  //将_display放入crud的columns的倒数第二列中(最后一列会影响固定列),可以通过setvalue修改行内数据域的_display,而不影响上层items的_display,用于批量编辑
8618
8833
  body.columns.splice(body.columns.length -1 , 0, {name: '_display',type: 'static', width: 1, placeholder: "",id: objectSchema.name + "_display_${_index}", tpl: "${''}"});
@@ -8978,7 +9193,7 @@ const getRecordPermissions = async (objectName, recordId)=>{
8978
9193
  * @Author: baozhoutao@steedos.com
8979
9194
  * @Date: 2022-07-05 15:55:39
8980
9195
  * @LastEditors: baozhoutao@steedos.com
8981
- * @LastEditTime: 2024-01-15 10:34:46
9196
+ * @LastEditTime: 2024-01-24 10:18:17
8982
9197
  * @Description:
8983
9198
  */
8984
9199
 
@@ -9077,7 +9292,9 @@ async function getRecordDetailRelatedListSchema(objectName, recordId, relatedObj
9077
9292
  const foreign_key_value = arr[2] ? arr[1]+'.'+arr[2] : arr[1];
9078
9293
  mainRelated[arr[0]] = foreign_key_value;
9079
9294
  }
9080
- }else {
9295
+ }
9296
+ // 防止related_lists中没有相关子表,但是details中有相关子表的情况
9297
+ if(!mainRelated[relatedObjectName]){
9081
9298
  const details = _$1.union(mainObjectUiSchema.details,mainObjectUiSchema.lookup_details) || [];
9082
9299
  for (const detail of details) {
9083
9300
  const arr = detail.split(".");
@@ -9166,7 +9383,7 @@ async function getRecordDetailRelatedListSchema(objectName, recordId, relatedObj
9166
9383
  amisSchema: {
9167
9384
  type: "service",
9168
9385
  id: componentId,
9169
- className: `steedos-record-related-list py-2 first:pt-0 border-b last:border-b-0 ${componentId} ${className}`,
9386
+ className: `steedos-record-related-list mb-4 last:mb-0 ${componentId} ${className}`,
9170
9387
  data: {
9171
9388
  relatedKey: relatedKey,
9172
9389
  listViewId: `amis-\${appId}-${relatedObjectName}-listview`,
@@ -9394,8 +9611,8 @@ async function getObjectRelatedListsMiniSchema(objectApiName){
9394
9611
  /*
9395
9612
  * @Author: baozhoutao@steedos.com
9396
9613
  * @Date: 2022-07-05 15:55:39
9397
- * @LastEditors: baozhoutao@steedos.com
9398
- * @LastEditTime: 2024-01-16 11:14:34
9614
+ * @LastEditors: liaodaxue
9615
+ * @LastEditTime: 2024-02-05 17:56:27
9399
9616
  * @Description:
9400
9617
  */
9401
9618
 
@@ -9751,6 +9968,8 @@ async function convertColumnsToTableFields(columns, uiSchema, ctx = {}) {
9751
9968
  const rfUiSchema = await getUISchema(filedInfo.reference_to);
9752
9969
  const rfFieldInfo = rfUiSchema.fields[displayName];
9753
9970
  fields.push(Object.assign({}, rfFieldInfo, { name: `${fieldName}__expand.${displayName}`, expand: true, expandInfo: { fieldName, displayName } }, ctx));
9971
+ }else if(filedInfo && filedInfo.type === 'object'){
9972
+ fields.push(uiSchema.fields[column]);
9754
9973
  }
9755
9974
  } else {
9756
9975
  if (uiSchema.fields[column]) {
@@ -9912,7 +10131,7 @@ async function getRecordDetailSchema(objectName, appId, props = {}){
9912
10131
  };
9913
10132
  const content = {
9914
10133
  "type": "tabs",
9915
- "className": "steedos-record-tabs bg-white p-4 m-0 mt-2 border-y",
10134
+ "className": "steedos-record-tabs bg-white p-4 mt-3 border-y",
9916
10135
  "contentClassName": "bg-none",
9917
10136
  "tabs": [
9918
10137
  detailed
@@ -10613,17 +10832,13 @@ function getReferenceToSync(field) {
10613
10832
 
10614
10833
  function getLookupSapceUserTreeSchema(isMobile){
10615
10834
  let apiAdaptor = `
10616
- // console.log("===getLookupSapceUserTreeSchema===", JSON.stringify(payload));
10617
10835
  const records = payload.data.options;
10618
- let isTreeOptionsComputed = false;
10619
- if(records.length === 1 && records[0].children){
10620
- isTreeOptionsComputed = true;
10621
- }
10622
- if(isTreeOptionsComputed){
10623
- return payload;
10624
- }
10625
10836
  const treeRecords = [];
10626
- const getChildren = (records, childrenIds) => {
10837
+ const getChildren = (currentRecord, records, childrenIds) => {
10838
+ if (currentRecord.children && typeof currentRecord.children[0] === "object") {
10839
+ // 考虑api配置了cache缓存的话,不会请求接口但是会重新进这个接收适配器脚本且payload.data.options返回的会是上一次计算结果,这里直接返回计算过的children
10840
+ return currentRecord.children;
10841
+ }
10627
10842
  if (!childrenIds) {
10628
10843
  return;
10629
10844
  }
@@ -10632,7 +10847,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10632
10847
  });
10633
10848
  _.each(children, (item) => {
10634
10849
  if (item.children) {
10635
- item.children = getChildren(records, item.children)
10850
+ item.children = getChildren(item, records, item.children)
10636
10851
  }else{
10637
10852
  item.children = [];
10638
10853
  }
@@ -10658,7 +10873,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10658
10873
 
10659
10874
  _.each(records, (record) => {
10660
10875
  if (record.noParent == 1) {
10661
- treeRecords.push(Object.assign({}, record, { children: getChildren(records, record.children) }));
10876
+ treeRecords.push(Object.assign({}, record, { children: getChildren(record, records, record.children) }));
10662
10877
  }
10663
10878
  });
10664
10879
  console.log(treeRecords)
@@ -10708,6 +10923,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10708
10923
  }
10709
10924
  },
10710
10925
  "label": "",
10926
+ "mode": "normal",
10711
10927
  "name": "organizations",
10712
10928
  "multiple": false,
10713
10929
  "joinValues": false,
@@ -10850,6 +11066,9 @@ async function lookupToAmisPicker(field, readonly, ctx){
10850
11066
  }
10851
11067
  });
10852
11068
 
11069
+ let listviewFilter = getListViewFilter(listView);
11070
+ let listviewFiltersFunction = listView && listView._filters;
11071
+
10853
11072
  let sort = "";
10854
11073
  if(listView){
10855
11074
  sort = getListViewSort(listView);
@@ -10896,7 +11115,7 @@ async function lookupToAmisPicker(field, readonly, ctx){
10896
11115
  Object.assign(api.data.$self, __changedSearchBoxValues, __changedFilterFormValues);
10897
11116
  }
10898
11117
  const selfData = JSON.parse(JSON.stringify(api.data.$self));
10899
- var filters = [];
11118
+ ${listviewFilter && !ctx.inFilterForm ? `var filters = ${JSON.stringify(listviewFilter)};` : 'var filters = [];'}
10900
11119
  var pageSize = api.data.pageSize || 10;
10901
11120
  var pageNo = api.data.pageNo || 1;
10902
11121
  var skip = (pageNo - 1) * pageSize;
@@ -10958,6 +11177,16 @@ async function lookupToAmisPicker(field, readonly, ctx){
10958
11177
  }
10959
11178
 
10960
11179
  const inFilterForm = ${ctx.inFilterForm};
11180
+
11181
+ const listviewFiltersFunction = ${listviewFiltersFunction};
11182
+
11183
+ if(listviewFiltersFunction && !inFilterForm){
11184
+ const _filters0 = listviewFiltersFunction(filters, api.data.$self.__super);
11185
+ if(_filters0 && _filters0.length){
11186
+ filters.push(_filters0);
11187
+ }
11188
+ }
11189
+
10961
11190
  const filtersFunction = ${field.filtersFunction || field._filtersFunction};
10962
11191
 
10963
11192
  if(filtersFunction && !inFilterForm){
@@ -11045,6 +11274,16 @@ async function lookupToAmisPicker(field, readonly, ctx){
11045
11274
  });
11046
11275
  payload.data.rows = treeRecords;
11047
11276
  }
11277
+ const result = payload.data.rows;
11278
+ if(result && result.length){
11279
+ const updatedResult = _.map(result, (element) => {
11280
+ const data = { ...element };
11281
+ // image字段值添加URL前缀
11282
+ ${getScriptForAddUrlPrefixForImgFields(___namespace.values(refObjectConfig.fields))}
11283
+ return data;
11284
+ });
11285
+ payload.data.rows = updatedResult;
11286
+ }
11048
11287
  return payload;
11049
11288
  `;
11050
11289
  if(field.optionsFunction || field._optionsFunction){
@@ -11076,13 +11315,15 @@ async function lookupToAmisPicker(field, readonly, ctx){
11076
11315
 
11077
11316
  pickerSchema.affixHeader = false;
11078
11317
 
11079
- var headerToolbarItems = [];
11318
+
11319
+
11320
+ pickerSchema.headerToolbar = getObjectHeaderToolbar(refObjectConfig, fieldsArr, ctx.formFactor, { isLookup: true, keywordsSearchBoxName });
11321
+
11080
11322
  if(referenceTo.objectName === "space_users" && field.reference_to_field === "user"){
11081
- headerToolbarItems = getLookupSapceUserTreeSchema(isMobile);
11323
+ pickerSchema.headerToolbar.push(getLookupSapceUserTreeSchema(isMobile));
11082
11324
  pickerSchema.className = pickerSchema.className || "" + " steedos-select-user";
11083
11325
  }
11084
-
11085
- pickerSchema.headerToolbar = getObjectHeaderToolbar(refObjectConfig, fieldsArr, ctx.formFactor, { headerToolbarItems, isLookup: true, keywordsSearchBoxName });
11326
+
11086
11327
  const isAllowCreate = refObjectConfig.permissions.allowCreate;
11087
11328
  const isCreate = ___namespace.isBoolean(field.create) ? field.create : true;
11088
11329
  // lookup字段配置过滤条件就强制不显示新建按钮
@@ -11195,8 +11436,19 @@ async function lookupToAmisPicker(field, readonly, ctx){
11195
11436
  pickerSchema.footerToolbar = ["pagination"];
11196
11437
  }
11197
11438
 
11439
+ if(field.inlineHelpText){
11440
+ pickerSchema.toolbarClassName = "hasHelpText";
11441
+ pickerSchema.headerToolbar = [{
11442
+ "type": "tpl",
11443
+ "tpl": field.inlineHelpText,
11444
+ "className": "text-secondary"
11445
+ }, ...pickerSchema.headerToolbar];
11446
+ }
11447
+ pickerSchema.className = (pickerSchema.className || "") + " steedos-lookup-crud";
11448
+
11198
11449
  const data = {
11199
11450
  type: getAmisStaticFieldType('picker', readonly),
11451
+ className: ctx.className || '',
11200
11452
  modalTitle: i18next__default["default"].t('frontend_form_please_select') + " " + refObjectConfig.label,
11201
11453
  labelField: referenceTo.labelField.name,
11202
11454
  valueField: referenceTo.valueField.name,
@@ -11270,6 +11522,9 @@ async function lookupToAmisSelect(field, readonly, ctx){
11270
11522
  const refObjectConfig = referenceTo && await getUISchema(referenceTo.objectName);
11271
11523
  let listView = getLookupListView(refObjectConfig);
11272
11524
 
11525
+ let listviewFilter = getListViewFilter(listView);
11526
+ let listviewFiltersFunction = listView && listView._filters;
11527
+
11273
11528
  let sort = "";
11274
11529
  if(listView){
11275
11530
  sort = getListViewSort(listView);
@@ -11299,7 +11554,7 @@ async function lookupToAmisSelect(field, readonly, ctx){
11299
11554
  apiInfo.data['rfield'] = `\${object_name}`;
11300
11555
  // [["_id", "=", "$${field.name}._id"],"or",["name", "contains", "$term"]]
11301
11556
  apiInfo.requestAdaptor = `
11302
- var filters = [];
11557
+ ${listviewFilter && !ctx.inFilterForm ? `var filters = ${JSON.stringify(listviewFilter)};` : 'var filters = [];'}
11303
11558
  var top = 200;
11304
11559
  if(api.data.$term){
11305
11560
  filters = [["${referenceTo?.NAME_FIELD_KEY || 'name'}", "contains", api.data.$term]];
@@ -11322,6 +11577,16 @@ async function lookupToAmisSelect(field, readonly, ctx){
11322
11577
  }
11323
11578
 
11324
11579
  const inFilterForm = ${ctx.inFilterForm};
11580
+
11581
+ const listviewFiltersFunction = ${listviewFiltersFunction};
11582
+
11583
+ if(listviewFiltersFunction && !inFilterForm){
11584
+ const _filters0 = listviewFiltersFunction(filters, api.data.$);
11585
+ if(_filters0 && _filters0.length){
11586
+ filters.push(_filters0);
11587
+ }
11588
+ }
11589
+
11325
11590
  const filtersFunction = ${field.filtersFunction || field._filtersFunction};
11326
11591
 
11327
11592
  if(filtersFunction && !inFilterForm){
@@ -11398,6 +11663,7 @@ async function lookupToAmisSelect(field, readonly, ctx){
11398
11663
  // 但是同时配置autoComplete和source会多请求一次接口
11399
11664
  // TODO:应该想办法把是否字段在子表组件内,即ctx.isInputTable,如果不在子表组件内不需要加source
11400
11665
  data.source = apiInfo;
11666
+ delete data.autoComplete;
11401
11667
  }
11402
11668
  //删除xlink:href中的rootUrl前缀,解决客户端svg为空的问题
11403
11669
  const select_menuTpl = `<span class='flex items-center mt-0.5'>
@@ -11444,7 +11710,8 @@ async function lookupToAmis(field, readonly, ctx){
11444
11710
  }
11445
11711
  // console.log(`lookupToAmis====`, field, readonly, ctx)
11446
11712
  if(readonly){
11447
- if(field.reference_to){
11713
+ if(field.reference_to && !field.isTableField){
11714
+ //isTableField只在grid字段内存在
11448
11715
  return {
11449
11716
  type: 'steedos-field',
11450
11717
  config: field,
@@ -11659,8 +11926,8 @@ if(typeof window != 'undefined'){
11659
11926
  /*
11660
11927
  * @Author: baozhoutao@steedos.com
11661
11928
  * @Date: 2023-01-13 17:27:54
11662
- * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
11663
- * @LastEditTime: 2023-08-28 17:45:38
11929
+ * @LastEditors: liaodaxue
11930
+ * @LastEditTime: 2024-02-04 17:29:54
11664
11931
  * @Description:
11665
11932
  */
11666
11933
 
@@ -11761,7 +12028,8 @@ const getHtmlFieldSchema = (field, readonly, ctx)=>{
11761
12028
  "title": "Insert",
11762
12029
  "items": "image link media addcomment pageembed codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime"
11763
12030
  }
11764
- }
12031
+ },
12032
+ "statusbar": false
11765
12033
  },
11766
12034
  "name": field.name
11767
12035
  }
@@ -12106,13 +12374,31 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12106
12374
  };
12107
12375
  break;
12108
12376
  case 'input-datetime-range':
12377
+ // convertData = {
12378
+ // type: "input-datetime-range",
12379
+ // inputFormat: 'YYYY-MM-DD HH:mm',
12380
+ // format:'YYYY-MM-DDTHH:mm:ss.SSSZ',
12381
+ // tpl: readonly ? Tpl.getDateTimeTpl(field) : null,
12382
+ // utc: true,
12383
+ // joinValues: false
12384
+ // }
12385
+ // 日期时间字段,按日期方式展现显示控件,用户不用关心小时分钟
12109
12386
  convertData = {
12110
- type: "input-datetime-range",
12111
- inputFormat: 'YYYY-MM-DD HH:mm',
12387
+ type: "input-date-range",
12388
+ inputFormat: "YYYY-MM-DD HH:mm",
12112
12389
  format:'YYYY-MM-DDTHH:mm:ss.SSSZ',
12113
12390
  tpl: readonly ? getDateTimeTpl(field) : null,
12114
12391
  utc: true,
12115
- joinValues: false
12392
+ joinValues: false,
12393
+ "shortcuts": [
12394
+ "thismonth",
12395
+ "2monthsago",
12396
+ "3monthslater",
12397
+ "prevquarter",
12398
+ "thisquarter",
12399
+ "thisyear",
12400
+ "lastYear"
12401
+ ]
12116
12402
  };
12117
12403
  break;
12118
12404
  case 'datetime':
@@ -12163,7 +12449,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12163
12449
  convertData = {
12164
12450
  type: getAmisStaticFieldType('datetime', readonly),
12165
12451
  inputFormat: 'YYYY-MM-DD HH:mm',
12166
- format: 'YYYY-MM-DDTHH:mm:ss.SSSZ',
12452
+ format: 'YYYY-MM-DDTHH:mm:00.000Z',
12167
12453
  tpl: readonly ? getDateTimeTpl(field) : null,
12168
12454
  utc: true,
12169
12455
  };
@@ -12294,6 +12580,36 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12294
12580
  convertData = {
12295
12581
  type: 'static-text'
12296
12582
  };
12583
+ }else if(field.autonumber_enable_modify){
12584
+ convertData = {
12585
+ "type": "input-group",
12586
+ "body": [
12587
+ {
12588
+ "type": "input-text",
12589
+ "name": field.name
12590
+ },
12591
+ {
12592
+ "type": "button",
12593
+ "label": "自动获取",
12594
+ "actionType": "ajax",
12595
+ "api": {
12596
+ "url": `\${context.rootUrl}/api/autonumber/generator/\${objectName}/${field.name}`,
12597
+ "method": "post",
12598
+ "headers": {
12599
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
12600
+ },
12601
+ "adaptor": `
12602
+ payload.data["${field.name}"] = payload.data && payload.data.autonumber;
12603
+ delete payload.data.autonumber;
12604
+ return payload;
12605
+ `
12606
+ },
12607
+ "messages": {
12608
+ "success": "获取成功"
12609
+ }
12610
+ }
12611
+ ]
12612
+ };
12297
12613
  }
12298
12614
  break;
12299
12615
  case 'url':
@@ -12499,12 +12815,13 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12499
12815
  break;
12500
12816
  }
12501
12817
  if(!___namespace.isEmpty(convertData)){
12818
+ const className = convertData.className;
12502
12819
  if(field.is_wide || convertData.type === 'group'){
12503
- convertData.className = 'col-span-2 m-0';
12820
+ convertData.className = className ? 'col-span-2 m-0 ' + className : 'col-span-2 m-0';
12504
12821
  }else {
12505
- convertData.className = 'm-0';
12822
+ convertData.className = className ? 'm-0 ' + className : 'm-0';
12506
12823
  }
12507
- if(readonly){
12824
+ if(readonly && ctx.mode !== 'edit'){
12508
12825
  convertData.className = `${convertData.className} border-b`;
12509
12826
  }
12510
12827
  if(readonly){
@@ -12512,11 +12829,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12512
12829
  }
12513
12830
 
12514
12831
  let fieldTypeClassName = ' steedos-' + convertData.type + (readonly ? '-readonly' : '-edit');
12515
- if (convertData.className) {
12516
- convertData.className = convertData.className + fieldTypeClassName;
12517
- } else {
12518
- convertData.className = fieldTypeClassName;
12519
- }
12832
+ convertData.className = convertData.className + fieldTypeClassName;
12520
12833
 
12521
12834
  if(field.visible_on && !ctx.inFilterForm){
12522
12835
  // convertData.visibleOn = `\$${field.visible_on.substring(1, field.visible_on.length -1).replace(/formData./g, '')}`;
@@ -12599,8 +12912,9 @@ async function getFieldSearchable(perField, permissionFields, ctx){
12599
12912
  fieldNamePrefix = `${fieldNamePrefix}between__`;
12600
12913
  }
12601
12914
  if(_field.type === 'datetime'){
12602
- // 特意改为日期范围而不是日期时间范围,因为搜索时一般精确到日期就足够了,需要精确到日期时间范围需要在字段上配置amis属性来实现
12603
- _field.type = 'input-date-range';
12915
+ // 这里如果想把搜索范围展示效果改为日期范围,不可以直接改为input-date-range,因为它们规则不一样,包括时区规则和小时分秒的存值规则都不一样
12916
+ // 所以想改为展示日期范围效果,只能改input-datetime-range类型本身的属性来实现
12917
+ _field.type = 'input-datetime-range';
12604
12918
  _field.is_wide = true;
12605
12919
  fieldNamePrefix = `${fieldNamePrefix}between__`;
12606
12920
  }
@@ -12786,6 +13100,13 @@ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectio
12786
13100
  }
12787
13101
  }
12788
13102
 
13103
+ fieldSetBody.forEach((field)=>{
13104
+ //判断label是否存在,不存在时将label的空占位元素隐藏
13105
+ if(!field.label){
13106
+ field.labelClassName = "none";
13107
+ }
13108
+ });
13109
+
12789
13110
  // fieldSet 已支持显隐控制
12790
13111
  const sectionFieldsVisibleOn = ___namespace.map(___namespace.compact(___namespace.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
12791
13112
  let visible = visibleOn;
@@ -12908,12 +13229,130 @@ async function getFormBody(permissionFields, formFields, ctx){
12908
13229
  return await getSections(permissionFields, formFields, ctx);
12909
13230
  }
12910
13231
 
13232
+ /*
13233
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
13234
+ * @Date: 2024-01-18 15:12:41
13235
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
13236
+ * @LastEditTime: 2024-01-18 15:12:49
13237
+ */
13238
+ /**
13239
+ * 生成符合标准uuid格式的36位满足唯一性的随机串
13240
+ * @returns uuid
13241
+ */
13242
+ function uuidv4() {
13243
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
13244
+ (c ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
13245
+ );
13246
+ }
13247
+
12911
13248
  /*
12912
13249
  * @Author: 殷亮辉 yinlianghui@hotoa.com
12913
13250
  * @Date: 2023-11-15 09:50:22
12914
13251
  * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12915
- * @LastEditTime: 2024-01-17 17:15:57
13252
+ * @LastEditTime: 2024-01-26 17:47:16
13253
+ */
13254
+
13255
+ /**
13256
+ * 子表组件字段值中每行数据补上字段值为空的的字段值,把值统一设置为空字符串,是为了解决amis amis 3.6/6.0 input-table组件bug:行中字段值为空时会显示为父作用域中的同名变量值,见:https://github.com/baidu/amis/issues/9520
13257
+ * amis #9520修正后此函数及相关代码可以移除
13258
+ * @param {*} value 子表组件字段值,数组
13259
+ * @param {*} fields 子表组件fields属性,数组
13260
+ * @returns 转换后的子表组件字段值
13261
+ */
13262
+ function getTableValueWithEmptyValue(value, fields) {
13263
+ return (value || []).map((itemValue) => {
13264
+ //这里不clone的话,会造成在pipeIn函数执行该函数后像pipeOut一样最终输出到表单项中,即库里字段值会被改了
13265
+ const newItemValue = _$1.clone(itemValue);
13266
+ (fields || []).forEach((itemField) => {
13267
+ if(itemField.name && (newItemValue[itemField.name] === undefined || newItemValue[itemField.name] === null)){
13268
+ // 这里newItemValue中不存在 itemField.name 属性,或者值为null时都会有“显示为父作用域中的同名变量值”的问题,所以null和undefined都要重置为空字符串
13269
+ // 实测数字、下拉框、多选lookup等字段类型重置为空字符串都不会有问题,而且实测amis from组件的清空表单字段值功能就是把表单中的各种字段类型设置为空字符串,所以看起来也符合amis规范
13270
+ newItemValue[itemField.name] = "";
13271
+ }
13272
+ if (newItemValue.children) {
13273
+ newItemValue.children = getTableValueWithEmptyValue(newItemValue.children, fields);
13274
+ }
13275
+ });
13276
+ return newItemValue;
13277
+ });
13278
+ }
13279
+
13280
+ /**
13281
+ * 把子表组件字段值中每行数据中经过上面getTableValueWithEmptyValue函数空字段值移除
13282
+ * amis #9520修正后此函数及相关代码可以移除
13283
+ * @param {*} value 子表组件字段值,数组
13284
+ * @param {*} fields 子表组件fields属性,数组
13285
+ * @returns 转换后的子表组件字段值
13286
+ */
13287
+ function getTableValueWithoutEmptyValue(value, fields) {
13288
+ return (value || []).map((itemValue) => {
13289
+ const newItemValue = _$1.clone(itemValue);
13290
+ (fields || []).forEach((itemField) => {
13291
+ if(itemField.name && (newItemValue[itemField.name] === "" || newItemValue[itemField.name] === undefined || newItemValue[itemField.name] === null)){
13292
+ // 这里额外把null和undefined值也删除掉纯粹是没必要输出保存它们
13293
+ delete newItemValue[itemField.name];
13294
+ }
13295
+ if (newItemValue.children) {
13296
+ newItemValue.children = getTableValueWithoutEmptyValue(newItemValue.children, fields);
13297
+ }
13298
+ });
13299
+ return newItemValue;
13300
+ });
13301
+ }
13302
+
13303
+ function getTablePrimaryKey(props) {
13304
+ return props.primaryKey || "_id";
13305
+ }
13306
+
13307
+ /**
13308
+ * 子表组件字段值中每行数据的补上唯一标识字段值,其值为随机uuid
13309
+ * @param {*} value 子表组件字段值,数组
13310
+ * @param {*} primaryKey 主键字段名,一般为_id
13311
+ * @returns 转换后的子表组件字段值
13312
+ */
13313
+ function getTableValueWithPrimaryKeyValue(value, primaryKey) {
13314
+ if (!primaryKey) {
13315
+ return value;
13316
+ }
13317
+ return (value || []).map((itemValue) => {
13318
+ //这里不clone的话,会造成在pipeIn函数执行该函数后像pipeOut一样最终输出到表单项中,即库里把primaryKey字段值保存了
13319
+ const newItemValue = _$1.clone(itemValue);
13320
+ if (newItemValue[primaryKey]) {
13321
+ if (newItemValue.children) {
13322
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
13323
+ }
13324
+ return newItemValue;
13325
+ }
13326
+ else {
13327
+ newItemValue[primaryKey] = uuidv4();
13328
+ if (newItemValue.children) {
13329
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
13330
+ }
13331
+ return newItemValue;
13332
+ }
13333
+ });
13334
+ }
13335
+
13336
+ /**
13337
+ * 子表组件字段值中每行数据的移除唯一标识字段值,因为该字段值一般只作临时标记,不存库
13338
+ * @param {*} value 子表组件字段值,数组
13339
+ * @param {*} primaryKey 主键字段名,一般为_id
13340
+ * @returns 转换后的子表组件字段值
12916
13341
  */
13342
+ function getTableValueWithoutPrimaryKeyValue(value, primaryKey) {
13343
+ if (!primaryKey) {
13344
+ return value;
13345
+ }
13346
+ return (value || []).map((itemValue) => {
13347
+ //这里clone只是为了保险,不是必须的,每次修改子表数据是否都会生成新的primaryKey字段值是由pipeOut中识别autoGeneratePrimaryKeyValue决定的,跟这里没关系
13348
+ const newItemValue = _$1.clone(itemValue);
13349
+ if (newItemValue.children) {
13350
+ newItemValue.children = getTableValueWithoutPrimaryKeyValue(newItemValue.children, primaryKey);
13351
+ }
13352
+ delete newItemValue[primaryKey];
13353
+ return newItemValue;
13354
+ });
13355
+ }
12917
13356
 
12918
13357
  /**
12919
13358
  * 子表组件字段值中每行数据的键值key移除指定前缀
@@ -12921,12 +13360,38 @@ async function getFormBody(permissionFields, formFields, ctx){
12921
13360
  * @param {*} fieldPrefix 字段前缀
12922
13361
  * @returns 转换后的子表组件字段值
12923
13362
  */
12924
- function getTableValueWithoutFieldPrefix(value, fieldPrefix){
13363
+ function getTableValueWithoutFieldPrefix(value, fieldPrefix) {
13364
+ let convertedValue = [];
13365
+ (value || []).forEach((itemValue) => {
13366
+ var newItemValue = {};
13367
+ for (let n in itemValue) {
13368
+ if (itemValue.hasOwnProperty(n)) {
13369
+ newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13370
+ }
13371
+ }
13372
+ convertedValue.push(newItemValue);
13373
+ });
13374
+ return convertedValue;
13375
+ }
13376
+
13377
+ /**
13378
+ * 子表组件字段值中每行数据的键值key补上指定前缀
13379
+ * @param {*} value 子表组件字段值,数组
13380
+ * @param {*} fieldPrefix 字段前缀
13381
+ * @param {*} primaryKey 主键字段名,主键不参与被键值key规则,需要排除,审批王amis表单也是这个规则
13382
+ * @returns 转换后的子表组件字段值
13383
+ */
13384
+ function getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey) {
12925
13385
  let convertedValue = [];
12926
- (value || []).forEach((itemValue)=>{
13386
+ (value || []).forEach((itemValue) => {
12927
13387
  var newItemValue = {};
12928
- for(let n in itemValue){
12929
- newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13388
+ for (let n in itemValue) {
13389
+ if (itemValue.hasOwnProperty(n) && typeof itemValue[n] !== undefined && n !== primaryKey) {
13390
+ newItemValue[`${fieldPrefix}${n}`] = itemValue[n];
13391
+ }
13392
+ }
13393
+ if (primaryKey && itemValue[primaryKey]) {
13394
+ newItemValue[primaryKey] = itemValue[primaryKey];
12930
13395
  }
12931
13396
  convertedValue.push(newItemValue);
12932
13397
  });
@@ -12939,7 +13404,7 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12939
13404
  * @param {*} fieldPrefix 字段前缀
12940
13405
  * @returns 转换后的子表组件字段值
12941
13406
  */
12942
- function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
13407
+ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix) {
12943
13408
  return (fields || []).map((item) => {
12944
13409
  const newItem = _$1.clone(item);//这里不clone的话,会造成子表组件重新render,从而审批王那边点开子表行编辑窗口时报错
12945
13410
  newItem.name = newItem.name.replace(new RegExp(`^${fieldPrefix}`), "");
@@ -12952,7 +13417,12 @@ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
12952
13417
  * @param {*} mode edit/new/readonly
12953
13418
  */
12954
13419
  function getFormFields(props, mode = "edit") {
12955
- return (props.fields || []).map(function (item) {
13420
+ let fieldPrefix = props.fieldPrefix;
13421
+ let fields = props.fields || [];
13422
+ if (fieldPrefix) {
13423
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13424
+ }
13425
+ return (fields || []).map(function (item) {
12956
13426
  let formItem = {
12957
13427
  "type": "steedos-field",
12958
13428
  "name": item.name,
@@ -12972,6 +13442,7 @@ function getInputTableCell(field, showAsInlineEditMode) {
12972
13442
  name: field.name,
12973
13443
  quickEdit: {
12974
13444
  "type": "steedos-field",
13445
+ "mode": "inline",
12975
13446
  "config": Object.assign({}, field, {
12976
13447
  label: false
12977
13448
  })
@@ -13024,7 +13495,12 @@ async function getInputTableColumns(props) {
13024
13495
  let inlineEditMode = props.inlineEditMode;
13025
13496
  let showAsInlineEditMode = inlineEditMode && props.editable;
13026
13497
  // 实测过,直接不生成对应的隐藏column并不会对input-table值造成丢失问题,隐藏的列字段值能正常维护
13027
- let fields = props.fields;
13498
+
13499
+ let fieldPrefix = props.fieldPrefix;
13500
+ let fields = props.fields || [];
13501
+ if (fieldPrefix) {
13502
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13503
+ }
13028
13504
  if (columns && columns.length) {
13029
13505
  return columns.map(function (column) {
13030
13506
  let field, extendColumnProps = {};
@@ -13046,8 +13522,26 @@ async function getInputTableColumns(props) {
13046
13522
  }
13047
13523
  }
13048
13524
  if (field) {
13049
- let tableCell = getInputTableCell(field, showAsInlineEditMode);
13050
- return Object.assign({}, tableCell, extendColumnProps);
13525
+ let mode = typeof extendColumnProps.inlineEditMode === "boolean" ?
13526
+ extendColumnProps.inlineEditMode : showAsInlineEditMode;
13527
+ let tableCell = getInputTableCell(field, mode);
13528
+ let className = "";
13529
+ //判断是否换行,目前规则默认换行
13530
+ if(extendColumnProps.wrap != true){
13531
+ className += " whitespace-nowrap ";
13532
+ }else {
13533
+ className += " break-words ";
13534
+ }
13535
+ //合并classname
13536
+ if (typeof extendColumnProps.className == "object") {
13537
+ className = {
13538
+ [className]: "true",
13539
+ ...extendColumnProps.className
13540
+ };
13541
+ } else if (typeof extendColumnProps.className == "string") {
13542
+ className = `${className} ${extendColumnProps.className} `;
13543
+ }
13544
+ return Object.assign({}, tableCell, extendColumnProps, {className});
13051
13545
  }
13052
13546
  else {
13053
13547
  return column;
@@ -13057,6 +13551,7 @@ async function getInputTableColumns(props) {
13057
13551
  else {
13058
13552
  return fields.map(function (field) {
13059
13553
  let tableCell = getInputTableCell(field, showAsInlineEditMode);
13554
+ tableCell.className = " whitespace-nowrap ";
13060
13555
  return tableCell;
13061
13556
  }) || [];
13062
13557
  }
@@ -13069,7 +13564,7 @@ async function getInputTableColumns(props) {
13069
13564
  */
13070
13565
  function getFormPagination(props, mode) {
13071
13566
  let showPagination = true;
13072
- if(mode === "new" && !!!props.editable){
13567
+ if (mode === "new" && !!!props.editable) {
13073
13568
  //不允许编辑只允许新建时不应该让用户操作翻页
13074
13569
  showPagination = false;
13075
13570
  }
@@ -13085,35 +13580,41 @@ function getFormPagination(props, mode) {
13085
13580
  let __formId = "${formId}";
13086
13581
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13087
13582
  let pageChangeDirection = context.props.pageChangeDirection;
13583
+ let mode = "${mode}";
13088
13584
  // event.data中的index和__page分别表示当前要把表单数据提交到的行索引和用于标定下一页页码的当前页页码
13089
13585
  // 一般来说__page = index + 1,但是可以让event.data中传入__page和index值不是这种联系。
13090
13586
  // 比如__page设置为3,index设置为0表示把当前表单数据提交到第一页,但是跳转到第4页,弹出的表单中底下的新增和复制按钮依赖了此功能
13091
13587
  // let currentPage = currentIndex + 1;
13092
13588
  let currentPage = event.data.__page;
13093
13589
  let currentIndex = event.data.index;
13094
- // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13095
- let currentFormValues = scope.getComponentById(__formId).getValues();
13096
- var parent = event.data.parent;
13097
- var __parentIndex = event.data.__parentIndex;
13098
- if(parent){
13099
- fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13100
- // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13101
- fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13102
- children: fieldValue[__parentIndex].children,
13103
- __fix_rerender_after_children_modified_tag: new Date().getTime()
13590
+ if(mode !== "readonly"){
13591
+ // 新建编辑时,翻页才需要把当前页表单保存,只读时直接翻页即可
13592
+ // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13593
+ let currentFormValues = scope.getComponentById(__formId).getValues();
13594
+ // 这里不clone的话,其值会带上__super属性
13595
+ currentFormValues = _.clone(currentFormValues);
13596
+ var parent = event.data.parent;
13597
+ var __parentIndex = event.data.__parentIndex;
13598
+ if(parent){
13599
+ fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13600
+ // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13601
+ fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13602
+ children: fieldValue[__parentIndex].children,
13603
+ __fix_rerender_after_children_modified_tag: new Date().getTime()
13604
+ });
13605
+ }
13606
+ else{
13607
+ fieldValue[currentIndex] = currentFormValues;
13608
+ }
13609
+ // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13610
+ doAction({
13611
+ "componentId": "${props.id}",
13612
+ "actionType": "setValue",
13613
+ "args": {
13614
+ "value": fieldValue
13615
+ }
13104
13616
  });
13105
13617
  }
13106
- else{
13107
- fieldValue[currentIndex] = currentFormValues;
13108
- }
13109
- // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13110
- doAction({
13111
- "componentId": "${props.id}",
13112
- "actionType": "setValue",
13113
- "args": {
13114
- "value": fieldValue
13115
- }
13116
- });
13117
13618
 
13118
13619
  // 以下是翻页逻辑,翻到下一页并把下一页内容显示到表单上
13119
13620
  let targetPage;
@@ -13162,9 +13663,14 @@ function getFormPagination(props, mode) {
13162
13663
  "onEvent": {
13163
13664
  "click": {
13164
13665
  "actions": [
13666
+ {
13667
+ "actionType": "validate",
13668
+ "componentId": formId
13669
+ },
13165
13670
  {
13166
13671
  "actionType": "custom",
13167
- "script": onPageChangeScript
13672
+ "script": onPageChangeScript,
13673
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13168
13674
  }
13169
13675
  ]
13170
13676
  }
@@ -13173,7 +13679,7 @@ function getFormPagination(props, mode) {
13173
13679
  {
13174
13680
  "type": "tpl",
13175
13681
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13176
- "tpl": "${__page}/${__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length}"
13682
+ "tpl": "${__page}/${__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length}"
13177
13683
  },
13178
13684
  {
13179
13685
  "type": "button",
@@ -13183,15 +13689,20 @@ function getFormPagination(props, mode) {
13183
13689
  "pageChangeDirection": "next",
13184
13690
  // "disabledOn": showPagination ? "${__page >= __tableItems.length}" : "true",
13185
13691
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13186
- "disabledOn": showPagination ? "${__page >= (__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length)}" : "true",
13692
+ "disabledOn": showPagination ? "${__page >= (__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length)}" : "true",
13187
13693
  "size": "sm",
13188
13694
  "id": buttonNextId,
13189
13695
  "onEvent": {
13190
13696
  "click": {
13191
13697
  "actions": [
13698
+ {
13699
+ "actionType": "validate",
13700
+ "componentId": formId
13701
+ },
13192
13702
  {
13193
13703
  "actionType": "custom",
13194
- "script": onPageChangeScript
13704
+ "script": onPageChangeScript,
13705
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13195
13706
  }
13196
13707
  ]
13197
13708
  }
@@ -13212,6 +13723,7 @@ function getFormPaginationWrapper(props, form, mode) {
13212
13723
  // console.log("==getFormPaginationWrapper===", props, mode);
13213
13724
  let serviceId = getComponentId("form_pagination", props.id);
13214
13725
  let tableServiceId = getComponentId("table_service", props.id);
13726
+ let primaryKey = getTablePrimaryKey(props);
13215
13727
  let innerForm = Object.assign({}, form, {
13216
13728
  "data": {
13217
13729
  // 这里加__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
@@ -13239,7 +13751,6 @@ function getFormPaginationWrapper(props, form, mode) {
13239
13751
  }
13240
13752
  ];
13241
13753
  let onServiceInitedScript = `
13242
-
13243
13754
  // 以下脚本解决了有时弹出编辑表单时,表单中的值比最后一次编辑保存的值会延迟一拍。
13244
13755
  // 比如:inlineEditMode模式时,用户在表格单元格中直接修改数据,然后弹出的表单form中并没有包含单元格中修改的内容
13245
13756
  // 另外有的地方在非inlineEditMode模式时也会有这种延迟一拍问题,比如对象字段中下拉框类型字段的”选择项“属性
@@ -13253,13 +13764,13 @@ function getFormPaginationWrapper(props, form, mode) {
13253
13764
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13254
13765
  // 这里如果不.clone的话,在弹出窗口中显示的子表组件,添加行后点窗口的取消按钮关闭窗口后无法把之前的操作还原,即把之前添加的行自动移除
13255
13766
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"] || []);
13256
- let fieldPrefix = "${props.fieldPrefix}";
13767
+ let fieldPrefix = "${props.fieldPrefix || ''}";
13257
13768
  if(fieldPrefix){
13258
13769
  let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
13259
13770
  lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
13260
13771
  }
13261
13772
  //不可以直接像event.data.__tableItems = lastestFieldValue; 这样整个赋值,否则作用域会断
13262
- let mode = "${mode}";
13773
+ let mode = "${mode || ''}";
13263
13774
  if(mode === "new"){
13264
13775
  // 点击子表组件底部新增按钮时新增一条空白行并自动翻页到新增行
13265
13776
  // 注意点击弹出的子表行详细表单中的新增按钮不会进此service init事件函数中
@@ -13285,10 +13796,20 @@ function getFormPaginationWrapper(props, form, mode) {
13285
13796
  var fieldValue = event.data.__tableItems;
13286
13797
  if(parent){
13287
13798
  // 如果是子行,即在节点嵌套情况下,当前节点如果是children属性下的子节点时,则算出其所属父行的索引值
13288
- var primaryKey = "${props.primaryKey}";
13799
+ var primaryKey = "${primaryKey}";
13289
13800
  event.data.__parentIndex = _.findIndex(fieldValue, function(item){
13290
13801
  return item[primaryKey] == parent[primaryKey];
13291
13802
  });
13803
+ if(event.data.__parentIndex < 0){
13804
+ let tableId = "${props.id}";
13805
+ let table = scope.getComponentById(tableId)
13806
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13807
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13808
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13809
+ event.data.__parentIndex = _.findIndex(table.props.value, function(item){
13810
+ return item[primaryKey] == parent[primaryKey];
13811
+ });
13812
+ }
13292
13813
  }
13293
13814
  `;
13294
13815
  let schema = {
@@ -13337,6 +13858,7 @@ function getFormPaginationWrapper(props, form, mode) {
13337
13858
  async function getForm(props, mode = "edit", formId) {
13338
13859
  let formFields = getFormFields(props, mode);
13339
13860
  let body = await getFormBody(null, formFields);
13861
+ let primaryKey = getTablePrimaryKey(props);
13340
13862
  if (!formId) {
13341
13863
  formId = getComponentId("form", props.id);
13342
13864
  }
@@ -13355,6 +13877,18 @@ async function getForm(props, mode = "edit", formId) {
13355
13877
  // 新增行弹出编辑行表单,在弹出之前已经不用先增加一行,因为在翻页service初始化的时候会判断mode为new时自动新增一行
13356
13878
  let onEditItemSubmitScript = `
13357
13879
  // let fieldValue = _.cloneDeep(event.data["${props.name}"]);
13880
+ let removeEmptyItems = function(items){
13881
+ let i = _.findIndex(items, function(item){
13882
+ return item === undefined
13883
+ });
13884
+ if(i > -1){
13885
+ items.splice(i, 1);
13886
+ removeEmptyItems(items);
13887
+ }
13888
+ }
13889
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13890
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13891
+ removeEmptyItems(event.data.__tableItems);
13358
13892
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13359
13893
  //这里加__super.__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
13360
13894
  // 比如“对象字段”对象options字段是一个子表字段,但是主表(即“对象字段”对象)中正好有一个名为index的字段
@@ -13363,6 +13897,8 @@ async function getForm(props, mode = "edit", formId) {
13363
13897
  var currentFormValues = JSON.parse(JSON.stringify(event.data));
13364
13898
  var parent = event.data.__super.__super.parent;
13365
13899
  var __parentIndex = event.data.__super.__super.__parentIndex;
13900
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13901
+ var primaryKey = "${primaryKey}";
13366
13902
  if(parent){
13367
13903
  fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13368
13904
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13372,6 +13908,8 @@ async function getForm(props, mode = "edit", formId) {
13372
13908
  });
13373
13909
  }
13374
13910
  else{
13911
+ // 这里currentFormValues中如果没有primaryKey字段值不用处理,因为组件的pipeIn/pipeOut中会为每行自动生成
13912
+ // 也不用担心复制行时_id会重复,因为点击复制按钮时已经处理过了
13375
13913
  fieldValue[currentIndex] = currentFormValues;
13376
13914
  }
13377
13915
  doAction({
@@ -13469,13 +14007,14 @@ async function getForm(props, mode = "edit", formId) {
13469
14007
  */
13470
14008
  async function getButtonActions(props, mode) {
13471
14009
  let actions = [];
14010
+ let primaryKey = getTablePrimaryKey(props);
13472
14011
  let formId = getComponentId("form", props.id);
13473
14012
  let dialogId = getComponentId("dialog", props.id);
13474
14013
  let buttonNextId = getComponentId("button_next", props.id);
13475
14014
  let formPaginationId = getComponentId("form_pagination", props.id);
13476
14015
  let parentFormData = "${__super.__super.__super.__super || {}}";
13477
14016
  let amisVersion = getComparableAmisVersion();
13478
- if(amisVersion < 3.6){
14017
+ if (amisVersion < 3.6) {
13479
14018
  parentFormData = "${__super.__super || {}}";
13480
14019
  }
13481
14020
  if (mode == "new" || mode == "edit") {
@@ -13511,13 +14050,35 @@ async function getButtonActions(props, mode) {
13511
14050
  // };
13512
14051
  let onSaveAndNewItemScript = `
13513
14052
  let scope = event.context.scoped;
14053
+ let removeEmptyItems = function(items){
14054
+ let i = _.findIndex(items, function(item){
14055
+ return item === undefined
14056
+ });
14057
+ if(i > -1){
14058
+ items.splice(i, 1);
14059
+ removeEmptyItems(items);
14060
+ }
14061
+ }
14062
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
14063
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
14064
+ removeEmptyItems(event.data.__tableItems);
13514
14065
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13515
14066
  // 新建一条空白行并保存到子表组件
13516
14067
  var parent = event.data.__super.parent;
13517
- var primaryKey = "${props.primaryKey}";
14068
+ var primaryKey = "${primaryKey}";
13518
14069
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13519
14070
  return item[primaryKey] == parent[primaryKey];
13520
14071
  });
14072
+ if(parent && __parentIndex < 0){
14073
+ let tableId = "${props.id}";
14074
+ let table = scope.getComponentById(tableId)
14075
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
14076
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
14077
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
14078
+ __parentIndex = _.findIndex(table.props.value, function(item){
14079
+ return item[primaryKey] == parent[primaryKey];
14080
+ });
14081
+ }
13521
14082
  if(parent){
13522
14083
  fieldValue[__parentIndex].children.push({});
13523
14084
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13551,14 +14112,42 @@ async function getButtonActions(props, mode) {
13551
14112
  let __formId = "${formId}";
13552
14113
  // let newItem = JSON.parse(JSON.stringify(event.data));
13553
14114
  let newItem = scope.getComponentById(__formId).getValues();//这里不可以用event.data,因为其拿到的是弹出表单时的初始值,不是用户实时填写的数据
14115
+ newItem = _.clone(newItem);
14116
+ let removeEmptyItems = function(items){
14117
+ let i = _.findIndex(items, function(item){
14118
+ return item === undefined
14119
+ });
14120
+ if(i > -1){
14121
+ items.splice(i, 1);
14122
+ removeEmptyItems(items);
14123
+ }
14124
+ }
14125
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
14126
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
14127
+ removeEmptyItems(event.data.__tableItems);
13554
14128
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13555
14129
  // 复制当前页数据到新建行并保存到子表组件
13556
14130
  // fieldValue.push(newItem);
13557
14131
  var parent = event.data.__super.parent;
13558
- var primaryKey = "${props.primaryKey}";
14132
+ var primaryKey = "${primaryKey}";
13559
14133
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13560
14134
  return item[primaryKey] == parent[primaryKey];
13561
14135
  });
14136
+ if(parent && __parentIndex < 0){
14137
+ let tableId = "${props.id}";
14138
+ let table = scope.getComponentById(tableId)
14139
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
14140
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
14141
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
14142
+ __parentIndex = _.findIndex(table.props.value, function(item){
14143
+ return item[primaryKey] == parent[primaryKey];
14144
+ });
14145
+ }
14146
+ if(newItem[primaryKey]){
14147
+ // 如果newItem已经有主键字段值,则重新生成新的主键值,否则会重复。
14148
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
14149
+ newItem[primaryKey] = uuidv4();
14150
+ }
13562
14151
  if(parent){
13563
14152
  fieldValue[__parentIndex].children.push(newItem);
13564
14153
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13589,13 +14178,13 @@ async function getButtonActions(props, mode) {
13589
14178
  `;
13590
14179
  let dialogButtons = [
13591
14180
  {
13592
- "type": "button",
13593
- "label": "完成",
13594
- "actionType": "confirm",
13595
- "level": "primary"
14181
+ "type": "button",
14182
+ "label": "完成",
14183
+ "actionType": "confirm",
14184
+ "level": "primary"
13596
14185
  }
13597
14186
  ];
13598
- if(props.addable){
14187
+ if (props.addable) {
13599
14188
  // 有新增行权限时额外添加新增和复制按钮
13600
14189
  dialogButtons = [
13601
14190
  {
@@ -13605,9 +14194,14 @@ async function getButtonActions(props, mode) {
13605
14194
  "onEvent": {
13606
14195
  "click": {
13607
14196
  "actions": [
14197
+ {
14198
+ "actionType": "validate",
14199
+ "componentId": formId
14200
+ },
13608
14201
  {
13609
14202
  "actionType": "custom",
13610
- "script": onSaveAndNewItemScript
14203
+ "script": onSaveAndNewItemScript,
14204
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13611
14205
  }
13612
14206
  ]
13613
14207
  }
@@ -13620,9 +14214,14 @@ async function getButtonActions(props, mode) {
13620
14214
  "onEvent": {
13621
14215
  "click": {
13622
14216
  "actions": [
14217
+ {
14218
+ "actionType": "validate",
14219
+ "componentId": formId
14220
+ },
13623
14221
  {
13624
14222
  "actionType": "custom",
13625
- "script": onSaveAndCopyItemScript
14223
+ "script": onSaveAndCopyItemScript,
14224
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13626
14225
  }
13627
14226
  ]
13628
14227
  }
@@ -13668,7 +14267,7 @@ async function getButtonActions(props, mode) {
13668
14267
  // 在节点嵌套情况下,当前节点正好是带children属性的节点的话,这里弹出的dialog映射到的会是children数组,这是amis目前的规则,
13669
14268
  // 所以这里加判断有children时,用__super.__super让映射到正确的作用域层,如果不加,则__tableItems取到的会是children数组,而不是整个子表组件的值
13670
14269
  "__tableItems": `\${((children ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13671
- },
14270
+ },
13672
14271
  "actions": dialogButtons,
13673
14272
  "onEvent": {
13674
14273
  "confirm": {
@@ -13766,7 +14365,10 @@ async function getButtonActions(props, mode) {
13766
14365
  // 为了解决"弹出的dialog窗口中子表组件会影响页面布局界面中父作用域字段值",比如设计字段布局微页面中的设置分组功能,弹出的就是子表dialog
13767
14366
  // 所以这里使用json|toJson转一次,断掉event.data.__tableItems与上层任用域中props.name的联系
13768
14367
  // "__tableItems": `\${${props.name}|json|toJson}`
13769
- "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
14368
+ // "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
14369
+ // 在节点嵌套情况下,当前节点正好是带children属性的节点的话,这里弹出的dialog映射到的会是children数组,这是amis目前的规则,
14370
+ // 所以这里加判断有children时,用__super.__super让映射到正确的作用域层,如果不加,则__tableItems取到的会是children数组,而不是整个子表组件的值
14371
+ "__tableItems": `\${((children ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13770
14372
  },
13771
14373
  }
13772
14374
  }
@@ -13782,13 +14384,24 @@ async function getButtonActions(props, mode) {
13782
14384
  let wrapperServiceData = wrapperService.getData();
13783
14385
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13784
14386
  // 这里_.clone是因为字段设计布局设置分组这种弹出窗口中的子表组件,直接删除后,点取消无法还原
14387
+ // 也因为这里clone没有直接删除,所以弹出编辑表单提交事件中event.data.__tableItems中取到的值会有被删除的行数据为undefined
13785
14388
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"]);
13786
14389
  var currentIndex = event.data.index;
13787
14390
  var parent = event.data.__super.parent;
13788
- var primaryKey = "${props.primaryKey}";
14391
+ var primaryKey = "${primaryKey}";
13789
14392
  var __parentIndex = parent && _.findIndex(lastestFieldValue, function(item){
13790
14393
  return item[primaryKey] == parent[primaryKey];
13791
14394
  });
14395
+ if(parent && __parentIndex < 0){
14396
+ let tableId = "${props.id}";
14397
+ let table = scope.getComponentById(tableId)
14398
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
14399
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
14400
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
14401
+ __parentIndex = _.findIndex(table.props.value, function(item){
14402
+ return item[primaryKey] == parent[primaryKey];
14403
+ });
14404
+ }
13792
14405
  if(parent){
13793
14406
  lastestFieldValue[__parentIndex].children.splice(currentIndex, 1);
13794
14407
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13800,6 +14413,11 @@ async function getButtonActions(props, mode) {
13800
14413
  else{
13801
14414
  lastestFieldValue.splice(currentIndex, 1);
13802
14415
  }
14416
+ let fieldPrefix = "${props.fieldPrefix || ''}";
14417
+ if(fieldPrefix){
14418
+ let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
14419
+ lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
14420
+ }
13803
14421
  doAction({
13804
14422
  "componentId": "${props.id}",
13805
14423
  "actionType": "setValue",
@@ -13869,46 +14487,77 @@ async function getButtonView(props) {
13869
14487
 
13870
14488
  async function getButtonDelete(props) {
13871
14489
  return {
13872
- "type": "button",
13873
- "label": "",
13874
- "icon": "fa fa-trash-alt",//不可以用fa-trash-o,因为设计字段布局界面中弹出的设置分组列表中显示不了这个图标
14490
+ "type": "dropdown-button",
13875
14491
  "level": "link",
13876
- "onEvent": {
13877
- "click": {
13878
- "actions": await getButtonActions(props, "delete")
14492
+ "icon": "fa fa-trash-alt",
14493
+ "size": "xs",
14494
+ "hideCaret": true,
14495
+ "closeOnClick": true,
14496
+ "body": [
14497
+ {
14498
+ "type": "wrapper",
14499
+ "size": "md",
14500
+ "className": "w-80",
14501
+ "body": [
14502
+ {
14503
+ "tpl": "确定要删除吗?",
14504
+ "type": "tpl"
14505
+ },
14506
+ {
14507
+ "type": "flex",
14508
+ "justify": "flex-end",
14509
+ "className": "mt-3",
14510
+ "items": [
14511
+ {
14512
+ "type": "button",
14513
+ "label": "取消",
14514
+ "className": "mr-2"
14515
+ },
14516
+ {
14517
+ "type": "button",
14518
+ "label": "删除",
14519
+ "level": "danger",
14520
+ "onEvent": {
14521
+ "click": {
14522
+ "actions": await getButtonActions(props, "delete")
14523
+ }
14524
+ }
14525
+ }
14526
+ ]
14527
+ }
14528
+ ]
13879
14529
  }
13880
- }
13881
- };
14530
+ ]
14531
+ }
13882
14532
  }
13883
14533
 
14534
+
13884
14535
  const getAmisInputTableSchema = async (props) => {
13885
14536
  if (!props.id) {
13886
14537
  props.id = "steedos_input_table_" + props.name + "_" + Math.random().toString(36).substr(2, 9);
13887
14538
  }
13888
- if (!props.primaryKey) {
13889
- props.primaryKey = "_id";
13890
- }
14539
+ let primaryKey = getTablePrimaryKey(props);
13891
14540
  let showOperation = props.showOperation;
13892
- if(showOperation !== false){
14541
+ if (showOperation !== false) {
13893
14542
  showOperation = true;
13894
14543
  }
13895
- // props.fieldPrefix = "project_milestone_";
13896
- if (props.fieldPrefix) {
13897
- props.fields = getTableFieldsWithoutFieldPrefix(props.fields, props.fieldPrefix);
14544
+ let fieldPrefix = props.fieldPrefix;
14545
+ let fields = props.fields || [];
14546
+ if (fieldPrefix) {
14547
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13898
14548
  }
13899
- console.log("=getAmisInputTableSchema==props.fields, props.fieldPrefix===", props.fields, props.fieldPrefix);
13900
14549
  let serviceId = getComponentId("table_service", props.id);
13901
14550
  let buttonsForColumnOperations = [];
13902
14551
  let inlineEditMode = props.inlineEditMode;
13903
14552
  let showAsInlineEditMode = inlineEditMode && props.editable;
13904
- if(showOperation){
14553
+ if (showOperation) {
13905
14554
  if (props.editable) {
13906
14555
  let showEditButton = true;
13907
14556
  if (showAsInlineEditMode) {
13908
14557
  // 始终显示弹出子表表单按钮,如果需要判断只在有列被隐藏时才需要显示弹出表单按钮放开下面的if逻辑就好
13909
14558
  showEditButton = true;
13910
14559
  // // inline edit模式下只在有列被隐藏时才需要显示编辑按钮
13911
- // if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length) {
14560
+ // if (props.columns && props.columns.length > 0 && props.columns.length < fields.length) {
13912
14561
  // showEditButton = true;
13913
14562
  // }
13914
14563
  // else {
@@ -13923,7 +14572,7 @@ const getAmisInputTableSchema = async (props) => {
13923
14572
  }
13924
14573
  else {
13925
14574
  // 只读时显示查看按钮
13926
- // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length)
14575
+ // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < fields.length)
13927
14576
  let buttonViewSchema = await getButtonView(props);
13928
14577
  buttonsForColumnOperations.push(buttonViewSchema);
13929
14578
  }
@@ -13932,9 +14581,10 @@ const getAmisInputTableSchema = async (props) => {
13932
14581
  buttonsForColumnOperations.push(buttonDeleteSchema);
13933
14582
  }
13934
14583
  }
14584
+ let amis = props["input-table"] || props.amis || {};//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
13935
14585
  let inputTableSchema = {
13936
14586
  "type": "input-table",
13937
- "label": props.label,
14587
+ "mode": "normal",
13938
14588
  "name": props.name,
13939
14589
  //不可以addable/editable/removable设置为true,因为会在原生的操作列显示操作按钮图标,此开关实测只控制这个按钮显示不会影响功能
13940
14590
  // "addable": props.addable,
@@ -13950,18 +14600,53 @@ const getAmisInputTableSchema = async (props) => {
13950
14600
  "showTableAddBtn": false,
13951
14601
  "showFooterAddBtn": false,
13952
14602
  "className": props.tableClassName,
14603
+ "pipeIn": (value, data) => {
14604
+ if (fieldPrefix) {
14605
+ value = getTableValueWithoutFieldPrefix(value, fieldPrefix);
14606
+ }
14607
+ value = getTableValueWithEmptyValue(value, fields);
14608
+ if (primaryKey) {
14609
+ // 这里临时给每行数据补上primaryKey字段值,如果库里不需要保存这里补上的字段值,pipeOut中会识别autoGeneratePrimaryKeyValue属性选择最终移除这里补上的字段值
14610
+ // 这里始终自动生成primaryKey字段值,而不是只在pipeOut输出整个子表字段值时才生成,是因为要支持当数据库里保存的子表字段行数据没有primaryKey字段值时的行嵌套模式(即节点的children属性)功能
14611
+ // 这里要注意,流程详细设置界面的字段设置功能中的子表组件中,数据库里保存的子表字段行数据是有primaryKey字段值的,它不依赖这里自动生成行primaryKey值功能
14612
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14613
+ }
14614
+ if (amis.pipeIn) {
14615
+ if (typeof amis.pipeIn === 'function') {
14616
+ return amis.pipeIn(value, data);
14617
+ }
14618
+ }
14619
+ return value;
14620
+ },
13953
14621
  "pipeOut": (value, data) => {
13954
- return (value || []).map(function(item){
14622
+ value = (value || []).map(function (item) {
13955
14623
  delete item.__fix_rerender_after_children_modified_tag;
13956
14624
  return item;
13957
14625
  });
14626
+ if (fieldPrefix) {
14627
+ value = getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey);
14628
+ }
14629
+ value = getTableValueWithoutEmptyValue(value, fields);
14630
+ if (props.autoGeneratePrimaryKeyValue === true) {
14631
+ // 如果需要把自动生成的primaryKey值输出保存的库中,则补全所有行中的primaryKey值
14632
+ // 这里如果不全部补全的话,初始从库里返回的字段值中拿到的行没primaryKey值的话就不会自动补上
14633
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14634
+ }
14635
+ else {
14636
+ // 默认情况下,也就是没有配置autoGeneratePrimaryKey时,最终输出的字段值要移除行中的primaryKey值
14637
+ // 需要注意如果没有配置autoGeneratePrimaryKey时,因为每次弹出行编辑窗口保存后都会先后进入pipeOut和pipeIn,
14638
+ // 这里删除掉了primaryKey值,所以primaryKey值每次弹出编辑窗口保存后都会给每行重新生成新的primaryKey值
14639
+ // 只有autoGeneratePrimaryKey配置为true时,每行的primaryKey字段值才会始终保持不变
14640
+ value = getTableValueWithoutPrimaryKeyValue(value, primaryKey);
14641
+ }
14642
+ if (amis.pipeOut) {
14643
+ if (typeof amis.pipeOut === 'function') {
14644
+ return amis.pipeOut(value, data);
14645
+ }
14646
+ }
14647
+ return value;
13958
14648
  }
13959
14649
  };
13960
- if(props.fieldPrefix){
13961
- inputTableSchema.pipeIn = (value, data) => {
13962
- return getTableValueWithoutFieldPrefix(value, props.fieldPrefix);
13963
- };
13964
- }
13965
14650
  if (buttonsForColumnOperations.length) {
13966
14651
  inputTableSchema.columns.push({
13967
14652
  "name": "__op__",
@@ -13970,16 +14655,18 @@ const getAmisInputTableSchema = async (props) => {
13970
14655
  "width": buttonsForColumnOperations.length > 1 ? "60px" : "20px"
13971
14656
  });
13972
14657
  }
13973
- if (showAsInlineEditMode) {
13974
- inputTableSchema.needConfirm = false;
13975
- }
13976
- let amis = props["input-table"] || props.amis;//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
14658
+ // if (showAsInlineEditMode) {
14659
+ // // 因为要支持不同的列上配置inlineEditMode属性,所有不可以把整个子表组件都设置为inlineEditMode
14660
+ // inputTableSchema.needConfirm = false;
14661
+ // }
13977
14662
  if (amis) {
13978
14663
  // 支持配置amis属性重写或添加最终生成的input-table中任何属性。
13979
14664
  delete amis.id;//如果steedos-input-table组件配置了amis.id属性,会造成新建编辑行功能不生效
14665
+ delete amis.pipeIn;//该属性在上面合并过了
14666
+ delete amis.pipeOut;//该属性在上面合并过了
13980
14667
  Object.assign(inputTableSchema, amis);
13981
14668
  }
13982
- const isAnyFieldHasDependOn = (props.fields || []).find(function (item) {
14669
+ const isAnyFieldHasDependOn = (fields || []).find(function (item) {
13983
14670
  return item.depend_on;
13984
14671
  });
13985
14672
  if (isAnyFieldHasDependOn) {
@@ -14012,11 +14699,31 @@ const getAmisInputTableSchema = async (props) => {
14012
14699
  "body": headerToolbar
14013
14700
  });
14014
14701
  }
14702
+ let className = "steedos-input-table";
14703
+
14704
+ if (typeof props.className == "object") {
14705
+ className = {
14706
+ [className]: "true",
14707
+ ...props.className
14708
+ };
14709
+ } else if (typeof props.className == "string") {
14710
+ className = `${className} ${props.className} `;
14711
+ }
14712
+
14015
14713
  let schema = {
14016
- "type": "service",
14017
- "body": schemaBody,
14018
- "className": props.className,
14019
- "id": serviceId
14714
+ "type": "control",
14715
+ "body": {
14716
+ "type": "service",
14717
+ "body": schemaBody,
14718
+ "id": serviceId
14719
+ },
14720
+ "label": props.label,
14721
+ "labelClassName": props.label ? props.labelClassName : "none",
14722
+ "labelRemark": props.labelRemark,
14723
+ "labelAlign": props.labelAlign,
14724
+ //控制control的mode属性,https://aisuda.bce.baidu.com/amis/zh-CN/components/form/formitem#表单项展示
14725
+ "mode": props.mode || null,
14726
+ className
14020
14727
  };
14021
14728
  // console.log("===schema===", schema);
14022
14729
  return schema;