@steedos-widgets/amis-lib 3.6.2-beta.9 → 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,14 +362,13 @@ 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
370
  const Router = {
371
- getTabDisplayAs(tab_id){
372
- const uiSchema = getUISchemaSync$1(tab_id, false);
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')
@@ -378,9 +377,12 @@ const Router = {
378
377
  // const key = `page_display`;
379
378
  const value = sessionStorage.getItem(key);
380
379
  let defaultDisplay = "grid";
381
- if(uiSchema.enable_split){
380
+ if(defaultEnableSplit === true){
382
381
  defaultDisplay = "split";
383
382
  }
383
+ if(window.innerWidth <= 768){
384
+ return "grid";
385
+ }
384
386
  return value ? value : defaultDisplay;
385
387
  },
386
388
 
@@ -413,8 +415,8 @@ const Router = {
413
415
  /*
414
416
  * @Author: baozhoutao@steedos.com
415
417
  * @Date: 2022-07-20 16:29:22
416
- * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
417
- * @LastEditTime: 2023-12-28 14:59:08
418
+ * @LastEditors: liaodaxue
419
+ * @LastEditTime: 2024-01-25 14:44:17
418
420
  * @Description:
419
421
  */
420
422
 
@@ -486,6 +488,25 @@ function getComparableAmisVersion() {
486
488
  }
487
489
  }
488
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
+
489
510
  /*
490
511
  * @Author: baozhoutao@steedos.com
491
512
  * @Date: 2022-05-23 09:53:08
@@ -548,7 +569,7 @@ function getSelectMap(selectOptions){
548
569
  _$1.forEach(selectOptions,(option)=>{
549
570
  const optionValue = option.value + '';
550
571
  const optionColor = option.color + '';
551
- if(optionColor){
572
+ if(optionColor && optionColor != "undefined"){
552
573
  const background = optionColor.charAt(0) === '#' ? optionColor : '#'+optionColor;
553
574
  const color = getContrastColor(background);
554
575
  const optionColorStyle = 'background:'+background+';color:'+color+';line-height:1.5rem';
@@ -1164,7 +1185,31 @@ const getAmisFileReadonlySchema = (steedosField)=>{
1164
1185
  }
1165
1186
  }
1166
1187
  if(type === 'file'){
1167
- 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
+ } : {
1168
1213
  type: amisFieldType,
1169
1214
  tpl: `
1170
1215
  <% let fileData = data._display.${steedosField.name}; if (fileData) { %>
@@ -1308,6 +1353,7 @@ var frontend_notifications$1 = "Notifications";
1308
1353
  var frontend_notifications_allread$1 = "Mark all as read";
1309
1354
  var frontend_notifications_allread_message$1 = "All marked as read";
1310
1355
  var frontend_profile$1 = "Profile";
1356
+ var switch_space$1 = "Switch Space";
1311
1357
  var frontend_about$1 = "About";
1312
1358
  var frontend_log_out$1 = "Log out";
1313
1359
  var frontend_listview_warning_start$1 = "The current ";
@@ -1395,6 +1441,7 @@ var en_us = {
1395
1441
  frontend_notifications_allread: frontend_notifications_allread$1,
1396
1442
  frontend_notifications_allread_message: frontend_notifications_allread_message$1,
1397
1443
  frontend_profile: frontend_profile$1,
1444
+ switch_space: switch_space$1,
1398
1445
  frontend_about: frontend_about$1,
1399
1446
  frontend_log_out: frontend_log_out$1,
1400
1447
  frontend_listview_warning_start: frontend_listview_warning_start$1,
@@ -1450,7 +1497,7 @@ var frontend_listview_control_delete_label = "删除";
1450
1497
  var frontend_listview_control_delete_confirm_text = "如果您删除此列表视图,该视图将为所有具备访问权限的用户永久删除。是否确定要删除?";
1451
1498
  var frontend_listview_control_delete_message_success = "删除成功";
1452
1499
  var frontend_listview_control_filters = "过滤设置";
1453
- var frontend_listview_control_filters_fields_extend = "条件组件1";
1500
+ var frontend_listview_control_filters_fields_extend = "条件组件";
1454
1501
  var frontend_listview_control_new_label = "新建";
1455
1502
  var frontend_listview_control_new_title = "新建 列表视图";
1456
1503
  var frontend_listview_control_new_message_success = "成功";
@@ -1484,6 +1531,7 @@ var frontend_notifications = "通知";
1484
1531
  var frontend_notifications_allread = "全部标记为已读";
1485
1532
  var frontend_notifications_allread_message = "已全部标记为已读";
1486
1533
  var frontend_profile = "个人资料";
1534
+ var switch_space = "切换工作区";
1487
1535
  var frontend_about = "关于";
1488
1536
  var frontend_log_out = "注销";
1489
1537
  var frontend_listview_warning_start = "当前";
@@ -1572,6 +1620,7 @@ var zh_cn = {
1572
1620
  frontend_notifications_allread: frontend_notifications_allread,
1573
1621
  frontend_notifications_allread_message: frontend_notifications_allread_message,
1574
1622
  frontend_profile: frontend_profile,
1623
+ switch_space: switch_space,
1575
1624
  frontend_about: frontend_about,
1576
1625
  frontend_log_out: frontend_log_out,
1577
1626
  frontend_listview_warning_start: frontend_listview_warning_start,
@@ -1626,7 +1675,7 @@ async function getQuickEditSchema(field, options){
1626
1675
  isAmisVersionforBatchEdit = window.Amis.version[0] >= 3 && window.Amis.version[2] >= 2;
1627
1676
  }
1628
1677
  const quickEditId = options.objectName + "_" + field.name + "_quickEdit";//定义快速编辑的表单id,用于setvalue传值
1629
- var quickEditSchema = { body: [], id: quickEditId };
1678
+ var quickEditSchema = { body: [], id: quickEditId, className: "steedos-table-quickEdit" };
1630
1679
  //select,avatar,image,file等组件无法行记录字段赋值,暂不支持批量编辑;
1631
1680
  if(field.type != 'avatar' && field.type != 'image' && field.type != 'file' && isAmisVersionforBatchEdit){
1632
1681
  const submitEvent = {
@@ -1885,7 +1934,8 @@ async function getQuickEditSchema(field, options){
1885
1934
  "failed": "失败了呢。。"
1886
1935
  }
1887
1936
  }
1888
- }
1937
+ },
1938
+ "expression": "${!recordPermissions.modifyAllRecords}"
1889
1939
  },
1890
1940
  {
1891
1941
  "actionType": "setValue",
@@ -1901,7 +1951,7 @@ async function getQuickEditSchema(field, options){
1901
1951
  "componentId": quickEditId,
1902
1952
  "args": {
1903
1953
  "value":{
1904
- "quickedit_record_permissions": "${event.data}"
1954
+ "quickedit_record_permissions": "${recordPermissions.modifyAllRecords ? {'allowEdit': true} : event.data}"
1905
1955
  }
1906
1956
  }
1907
1957
  }
@@ -1965,7 +2015,7 @@ async function getQuickEditSchema(field, options){
1965
2015
  `
1966
2016
  }
1967
2017
  },
1968
- "expression":"${event.data.value}"
2018
+ "expression":"${event.data.value && !recordPermissions.modifyAllRecords}"
1969
2019
  },
1970
2020
  {
1971
2021
  "actionType": "setValue",
@@ -1996,10 +2046,20 @@ async function getQuickEditSchema(field, options){
1996
2046
  "script": `
1997
2047
  const noPermission = event.data.noPermission;
1998
2048
  const crudComponent = event.context.scoped.getComponentById("${options.crudId}");
1999
- const selectedItems = crudComponent && crudComponent.props.store.selectedItems.concat();
2049
+ let selectedItems = crudComponent && crudComponent.props.store.selectedItems.concat();
2000
2050
  noPermission.forEach(function (item) {
2001
2051
  crudComponent && crudComponent.unSelectItem(_.find(selectedItems,{_id:item}));
2052
+ _.remove(selectedItems, (selected) => selected._id === item);
2002
2053
  })
2054
+ doAction({
2055
+ "componentId": "${quickEditId}",
2056
+ "actionType": "setValue",
2057
+ "args": {
2058
+ "value": {
2059
+ selectedItems
2060
+ }
2061
+ }
2062
+ });
2003
2063
  `
2004
2064
  },
2005
2065
  {
@@ -2060,7 +2120,7 @@ async function getQuickEditSchema(field, options){
2060
2120
  }
2061
2121
 
2062
2122
  function getFieldWidth(width){
2063
- const defaultWidth = "unset";//用于使table内的td标签下生成div,实现将快速编辑按钮固定在右侧的效果,并不是为了unset效果
2123
+ const defaultWidth = null;
2064
2124
  if(typeof width == 'string'){
2065
2125
  if(isNaN(width)){
2066
2126
  return width || defaultWidth;
@@ -2090,22 +2150,35 @@ async function getTableColumns(fields, options){
2090
2150
  //增加quickEdit属性,实现快速编辑
2091
2151
  const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
2092
2152
  let className = "";
2093
- if(field.wrap != true){
2094
- if(field.wrap != false && field.is_wide){
2095
- className += " break-words ";
2096
- }else {
2153
+ const bowserType = getBowserType();
2154
+ if(bowserType === "Safari"){
2155
+ className += " whitespace-nowrap ";
2156
+ }else {
2157
+ if(field.wrap != true){
2097
2158
  className += " whitespace-nowrap ";
2159
+ }else {
2160
+ className += " break-words ";
2098
2161
  }
2099
- }else {
2100
- className += " break-words ";
2101
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} `;
2171
+ }
2172
+ let fieldAmis = ___namespace.clone(field.amis);
2173
+ delete fieldAmis?.className;
2174
+
2102
2175
  let columnItem;
2103
2176
  if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
2104
2177
  const previewFileScript = `
2105
2178
  var data = event.data;
2106
2179
  var file_name = data.versions ? data.name : "${field.label}";
2107
- var file_id = data._id;
2108
- 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});
2109
2182
  `;
2110
2183
  columnItem = {
2111
2184
  "type": "button",
@@ -2130,11 +2203,11 @@ async function getTableColumns(fields, options){
2130
2203
  "expression": "!!!(window && window.nw && window.nw.require)"//浏览器上直接下载
2131
2204
  },
2132
2205
  {
2133
- "args": {},
2134
- "actionType": "custom",
2135
- "script": previewFileScript,
2136
- // "expression": "!!window?.nw?.require" //PC客户端预览附件
2137
- "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客户端预览附件
2138
2211
  }
2139
2212
  ]
2140
2213
  }
@@ -2149,7 +2222,7 @@ async function getTableColumns(fields, options){
2149
2222
  toggled: field.toggled,
2150
2223
  static: true,
2151
2224
  className,
2152
- }, field.amis, {name: field.name});
2225
+ }, fieldAmis, {name: field.name});
2153
2226
  }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
2154
2227
  columnItem = Object.assign({}, {
2155
2228
  type: "switch",
@@ -2160,7 +2233,7 @@ async function getTableColumns(fields, options){
2160
2233
  static: true,
2161
2234
  className,
2162
2235
  ...getAmisFileReadonlySchema(field)
2163
- }, field.amis, {name: field.name});
2236
+ }, fieldAmis, {name: field.name});
2164
2237
  }
2165
2238
  else if(field.type === 'select'){
2166
2239
  const map = getSelectMap(field.options);
@@ -2175,7 +2248,7 @@ async function getTableColumns(fields, options){
2175
2248
  className,
2176
2249
  inputClassName: "inline",
2177
2250
  static: true,
2178
- }, field.amis, {name: field.name});
2251
+ }, fieldAmis, {name: field.name});
2179
2252
  }
2180
2253
  else {
2181
2254
  const tpl = await getFieldTpl(field, options);
@@ -2202,15 +2275,6 @@ async function getTableColumns(fields, options){
2202
2275
  // }
2203
2276
 
2204
2277
  //field上的amis属性里的clssname需要单独判断类型合并
2205
- if (typeof field.amis?.className == "object") {
2206
- className = {
2207
- [className]: "true",
2208
- ...field.amis.className
2209
- };
2210
- } else if (typeof field.amis?.className == "string") {
2211
- className = `${className} ${field.amis.className} `;
2212
- }
2213
- delete field.amis?.className;
2214
2278
 
2215
2279
  if(!field.hidden && !field.extra){
2216
2280
  columnItem = Object.assign({}, {
@@ -2227,7 +2291,7 @@ async function getTableColumns(fields, options){
2227
2291
  static: true,
2228
2292
  options: field.type === 'html' ? {html: true} : null
2229
2293
  // toggled: true
2230
- }, field.amis, {name: field.name});
2294
+ }, fieldAmis, {name: field.name});
2231
2295
 
2232
2296
  if(field.type === 'color'){
2233
2297
  columnItem.type = 'color';
@@ -2423,10 +2487,10 @@ async function getMobileTableColumns(fields, options){
2423
2487
  if(value.url){
2424
2488
  cms_url = value.url;
2425
2489
  }else{
2426
- cms_url = "/api/files/files/"+value+"?download=true"
2490
+ cms_url = Steedos.absoluteUrl("/api/files/files/"+value+"?download=true");
2427
2491
  }
2428
2492
  }
2429
- Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
2493
+ Steedos.cordovaDownload(encodeURI(cms_url), event.data.name);
2430
2494
  `,
2431
2495
  "actionType": "custom"
2432
2496
  }
@@ -2926,6 +2990,21 @@ async function getTableApi(mainObject, fields, options){
2926
2990
  return api;
2927
2991
  `;
2928
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
+
2929
3008
  if(api.body.listName == "recent"){
2930
3009
  payload.data.rows = _.sortBy(payload.data.rows, function(item){
2931
3010
  return _.indexOf(api.body._ids, item._id)
@@ -2950,7 +3029,13 @@ async function getTableApi(mainObject, fields, options){
2950
3029
  value = [value]
2951
3030
  };
2952
3031
  if(field.type === 'file'){
2953
- 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
+ });
2954
3039
  }else{
2955
3040
  item[key] = _.map(value, (item)=>{
2956
3041
  if(field.type === 'image'){
@@ -2992,15 +3077,8 @@ async function getTableApi(mainObject, fields, options){
2992
3077
  }
2993
3078
  });
2994
3079
  };
2995
- let isTreeOptionsComputed = false;
2996
- if(records.length === 1 && records[0].children){
2997
- isTreeOptionsComputed = true;
2998
- }
2999
- if(!isTreeOptionsComputed){
3000
- // 如果api接口设置在缓存,缓存期间并不会重新请求接口,payload.data.rows是上次计算后的结果
3001
- payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
3002
- assignIndexToTreeRecords(payload.data.rows, '');
3003
- }
3080
+ payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
3081
+ assignIndexToTreeRecords(payload.data.rows, '');
3004
3082
  }
3005
3083
 
3006
3084
 
@@ -3059,11 +3137,10 @@ async function getTableApi(mainObject, fields, options){
3059
3137
  };
3060
3138
  let formFactor = "${options.formFactor}";
3061
3139
  if(formFactor !== "SMALL"){
3062
- const listviewComponent = $(".steedos-object-listview .antd-Table-table");
3063
- const firstListviewComponent = listviewComponent && listviewComponent[0];
3064
- if(firstListviewComponent){
3140
+ const lisviewDom = document.querySelector(".steedos-object-listview .antd-Table-table");
3141
+ if(lisviewDom){
3065
3142
  setTimeout(()=>{
3066
- firstListviewComponent.scrollIntoView();
3143
+ lisviewDom.scrollIntoView();
3067
3144
  }, 600);
3068
3145
  }
3069
3146
  }
@@ -4896,9 +4973,16 @@ const getSchema$2 = (uiSchema) => {
4896
4973
  "form": {
4897
4974
  debug: false,
4898
4975
  resetAfterSubmit: false,
4976
+ data: {
4977
+ editFormInited: true,
4978
+ },
4899
4979
  initApi: {
4980
+ method: 'GET',
4900
4981
  url: '/api/v1/queue_import_history/${recordId}?fields=["state"]',
4901
4982
  sendOn: 'this.recordId',
4983
+ data: null,
4984
+ requestAdaptor: "return api;",
4985
+ adaptor: "return payload;",
4902
4986
  responseData: {
4903
4987
  importState: "${state}"
4904
4988
  }
@@ -5770,7 +5854,7 @@ async function getObjectFieldsFilterFormSchema(ctx) {
5770
5854
  const formSchema = {
5771
5855
  "type": "service",
5772
5856
  "visibleOn": "this.filterFormSearchableFields && this.filterFormSearchableFields.length",
5773
- "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",
5774
5858
  "style":{
5775
5859
  "max-height":ctx.formFactor === 'SMALL'?"30vh":"unset"
5776
5860
  },
@@ -6357,7 +6441,7 @@ async function getObjectFieldsFilterBarSchema(objectSchema, ctx) {
6357
6441
  "className": "slds-filters"
6358
6442
  },
6359
6443
  "size": "xs",
6360
- "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"}`,
6361
6445
  "visibleOn": "this.showFieldsFilter",
6362
6446
  },
6363
6447
  "className": "bg-white"
@@ -6545,7 +6629,7 @@ async function getObjectListHeaderSecordLine(objectSchema, listViewName, ctx) {
6545
6629
  "icon": "fa fa-refresh",
6546
6630
  "actionType": "reload",
6547
6631
  "target": amisListViewId,
6548
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
6632
+ "className": "bg-white p-2 rounded text-gray-500"
6549
6633
  },
6550
6634
  fieldsFilterButtonSchema,
6551
6635
  // {
@@ -6553,7 +6637,7 @@ async function getObjectListHeaderSecordLine(objectSchema, listViewName, ctx) {
6553
6637
  // "label": "",
6554
6638
  // "icon": "fa fa-filter",
6555
6639
  // "actionType": "custom",
6556
- // "className": "bg-transparent p-2 rounded border-gray-300 text-gray-500",
6640
+ // "className": "bg-transparent p-2 rounded text-gray-500",
6557
6641
  // "id": "u:c20cb87d96c9",
6558
6642
  // "onEvent": {
6559
6643
  // "click": {
@@ -6601,7 +6685,7 @@ function getObjectListHeader$1(objectSchema, listViewName, ctx) {
6601
6685
  let headerSchema = [{
6602
6686
  "type": "wrapper",
6603
6687
  "body": body,
6604
- "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`
6605
6689
  }];
6606
6690
  return headerSchema;
6607
6691
  }
@@ -6736,7 +6820,7 @@ async function getObjectRecordDetailHeader(objectSchema, recordId, options) {
6736
6820
  let body = [
6737
6821
  {
6738
6822
  "type": "wrapper",
6739
- "className": "p-4 bg-gray-100 border-b",
6823
+ "className": "p-4 border-b",
6740
6824
  "body": [
6741
6825
  {
6742
6826
  "type": "grid",
@@ -6801,25 +6885,25 @@ async function getObjectRecordDetailHeader(objectSchema, recordId, options) {
6801
6885
  });
6802
6886
 
6803
6887
  // 注意: 以下注释不能删除. tailwind css 动态编译时会识别以下注释, 生成对应的样式
6804
- // xl:grid-cols-1
6805
- // xl:grid-cols-2
6806
- // xl:grid-cols-3
6807
- // xl:grid-cols-4
6808
- // xl:grid-cols-5
6809
- // xl:grid-cols-6
6810
- // xl:grid-cols-7
6811
- // xl:grid-cols-8
6812
- // xl:grid-cols-9
6813
- // xl:grid-cols-10
6814
- // xl:grid-cols-11
6815
- // xl:grid-cols-12
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
6816
6900
 
6817
6901
  body.push({
6818
6902
  "type": "wrapper",
6819
6903
  "body": {
6820
6904
  "type": "form",
6821
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
6822
- "className": `gap-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-${max}`,
6906
+ "className": `gap-2 grid grid-cols-1 lg:grid-cols-${max}`,
6823
6907
  "wrapWithPanel": false,
6824
6908
  "actions": [],
6825
6909
  "body": details,
@@ -6904,7 +6988,7 @@ async function getObjectRecordDetailRelatedListHeader(relatedObjectSchema, relat
6904
6988
  "className": "flex justify-between"
6905
6989
  }
6906
6990
  ],
6907
- "className": "steedos-record-related-header py-2 px-0"
6991
+ "className": "steedos-record-related-header py-2 px-3 bg-gray-50 border"
6908
6992
  };
6909
6993
  return recordRelatedListHeader;
6910
6994
  }
@@ -6947,6 +7031,7 @@ const getNewListviewButtonSchema = ()=>{
6947
7031
  "objectApiName": "object_listviews",
6948
7032
  "recordId": "",
6949
7033
  "mode": "edit",
7034
+ "layout": "normal",
6950
7035
  "defaultData": {
6951
7036
  "&": "${list_view}",
6952
7037
  "name":"",
@@ -6954,8 +7039,16 @@ const getNewListviewButtonSchema = ()=>{
6954
7039
  "filters":"",
6955
7040
  "shared":false,
6956
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
6957
7050
  },
6958
- "fieldsExtend": fieldsExtend$4(),
7051
+ "fieldsExtend": fieldsExtend$5(),
6959
7052
  "fields": fields$1(),
6960
7053
  "onEvent": {
6961
7054
  "submitSucc": {
@@ -7006,14 +7099,17 @@ function fields$1(){
7006
7099
  "mobile_columns",
7007
7100
  "searchable_fields",
7008
7101
  "is_system",
7009
- "shared"
7102
+ "shared",
7103
+ "shared_to",
7104
+ "shared_to_organizations"
7010
7105
  ]
7011
7106
  }
7012
7107
 
7013
- function fieldsExtend$4(){
7108
+ function fieldsExtend$5(){
7014
7109
  return {
7015
7110
  "group": "",
7016
7111
  "label": {
7112
+ "group": "",
7017
7113
  "is_wide": true
7018
7114
  },
7019
7115
  "name": {
@@ -7095,9 +7191,19 @@ function fieldsExtend$4(){
7095
7191
  "shared": {
7096
7192
  "group": "",
7097
7193
  "amis": {
7098
- "visibleOn": "${global.user.is_space_admin}"
7194
+ "visibleOn": "${false}"
7099
7195
  }
7100
7196
  },
7197
+ "shared_to": {
7198
+ "group": "",
7199
+ "amis":{
7200
+ "type": "radios",
7201
+ "inline": false
7202
+ }
7203
+ },
7204
+ "shared_to_organizations": {
7205
+ "group": ""
7206
+ },
7101
7207
  "filters": {
7102
7208
  "group": "",
7103
7209
  "amis": {
@@ -7135,14 +7241,23 @@ const getCopyListviewButtonSchema = ()=>{
7135
7241
  "objectApiName": "object_listviews",
7136
7242
  "recordId": "",
7137
7243
  "mode": "edit",
7244
+ "layout": "normal",
7138
7245
  "defaultData": {
7139
7246
  "&": "${list_view}",
7140
7247
  "name":"",
7141
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'),
7142
7249
  "shared":false,
7143
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
7144
7259
  },
7145
- "fieldsExtend": fieldsExtend$3(),
7260
+ "fieldsExtend": fieldsExtend$4(),
7146
7261
  "fields": fields(),
7147
7262
  "onEvent": {
7148
7263
  "submitSucc": {
@@ -7190,13 +7305,16 @@ function fields(){
7190
7305
  "mobile_columns.$.field",
7191
7306
  "searchable_fields.$.field",
7192
7307
  "is_system",
7193
- "shared"
7308
+ "shared",
7309
+ "shared_to",
7310
+ "shared_to_organizations"
7194
7311
  ]
7195
7312
  }
7196
7313
 
7197
- function fieldsExtend$3(){
7314
+ function fieldsExtend$4(){
7198
7315
  return {
7199
7316
  "label": {
7317
+ "group": "",
7200
7318
  "is_wide": true
7201
7319
  },
7202
7320
  "name": {
@@ -7246,10 +7364,21 @@ function fieldsExtend$3(){
7246
7364
  }
7247
7365
  },
7248
7366
  "shared": {
7367
+ "group": "",
7249
7368
  "amis": {
7250
- "visibleOn": "${global.user.is_space_admin}"
7369
+ "visibleOn": "${false}"
7251
7370
  }
7252
7371
  },
7372
+ "shared_to": {
7373
+ "group": "",
7374
+ "amis":{
7375
+ "type": "radios",
7376
+ "inline": false
7377
+ }
7378
+ },
7379
+ "shared_to_organizations": {
7380
+ "group": ""
7381
+ },
7253
7382
  "filters": {
7254
7383
  "group": "",
7255
7384
  "amis": {
@@ -7259,6 +7388,12 @@ function fieldsExtend$3(){
7259
7388
  }
7260
7389
  }
7261
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
+ */
7262
7397
  const getRenameListviewButtonSchema = ()=>{
7263
7398
  return {
7264
7399
  "type": "button",
@@ -7284,6 +7419,7 @@ const getRenameListviewButtonSchema = ()=>{
7284
7419
  "label": "对象表单",
7285
7420
  "objectApiName": "object_listviews",
7286
7421
  "recordId": "${recordId}",
7422
+ "layout": "normal",
7287
7423
  "mode": "edit",
7288
7424
  "fields": [
7289
7425
  "label"
@@ -7318,6 +7454,12 @@ const getRenameListviewButtonSchema = ()=>{
7318
7454
  }
7319
7455
  };
7320
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
+ */
7321
7463
  const getSetListviewShareButtonSchema = ()=>{
7322
7464
  return {
7323
7465
  "type": "button",
@@ -7333,6 +7475,8 @@ const getSetListviewShareButtonSchema = ()=>{
7333
7475
  "title": i18next__default["default"].t('frontend_listview_control_share'),
7334
7476
  "data": {
7335
7477
  "recordId": "${uiSchema.list_views[listName]._id}",
7478
+ "appId": "${appId}",
7479
+ "global": "${global}",
7336
7480
  "context": "${context}"
7337
7481
  },
7338
7482
  "body": [
@@ -7342,9 +7486,12 @@ const getSetListviewShareButtonSchema = ()=>{
7342
7486
  "objectApiName": "object_listviews",
7343
7487
  "recordId": "${recordId}",
7344
7488
  "mode": "edit",
7489
+ "layout": "normal",
7345
7490
  "fields": [
7346
- "shared"
7347
- ]
7491
+ "shared_to",
7492
+ "shared_to_organizations"
7493
+ ],
7494
+ "fieldsExtend": fieldsExtend$3(),
7348
7495
  }
7349
7496
  ],
7350
7497
  "showCloseButton": true,
@@ -7362,6 +7509,21 @@ const getSetListviewShareButtonSchema = ()=>{
7362
7509
  }
7363
7510
  };
7364
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
+
7365
7527
  const getSetListviewFiltersButtonSchema = ()=>{
7366
7528
  return {
7367
7529
  "type": "button",
@@ -7493,10 +7655,12 @@ function apiRequestAdaptor$2(){
7493
7655
  function fieldsExtend$2(){
7494
7656
  return {
7495
7657
  "filters": {
7658
+ "label": "",
7659
+ "group": "",
7496
7660
  "visible_on": "true",
7497
7661
  "amis": {
7498
7662
  "type": "condition-builder",
7499
- "label": i18next__default["default"].t('frontend_listview_control_filters_fields_extend'),
7663
+ // "label": i18next.t('frontend_listview_control_filters_fields_extend'),
7500
7664
  "source": {
7501
7665
  "method": "get",
7502
7666
  "url": "${context.rootUrl}/service/api/amis-metadata-listviews/getFilterFields?objectName=${targetObjectName}",
@@ -7539,6 +7703,7 @@ const getSetListviewColumnsButtonSchema = ()=>{
7539
7703
  "objectApiName": "object_listviews",
7540
7704
  "recordId": "${recordId}",
7541
7705
  "mode": "edit",
7706
+ "layout": "normal",
7542
7707
  "fieldsExtend": fieldsExtend$1(),
7543
7708
  "initApiAdaptor": initApiAdaptor$1(),
7544
7709
  "apiRequestAdaptor": apiRequestAdaptor$1(),
@@ -7735,6 +7900,8 @@ const getSetListviewSortButtonSchema = ()=>{
7735
7900
  function fieldsExtend(){
7736
7901
  return {
7737
7902
  "sort": {
7903
+ "label": "",
7904
+ "group": "",
7738
7905
  "amis": {
7739
7906
  "type": "tabs-transfer",
7740
7907
  "sortable": true,
@@ -7862,7 +8029,7 @@ const getSettingListviewToolbarButtonSchema = ()=>{
7862
8029
  "icon": "fa fa-cog",
7863
8030
  //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,为保持统一,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
7864
8031
  // "tooltip": i18next.t('frontend_button_listview_control_tooltip'),
7865
- "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",
7866
8033
  "align": "right",
7867
8034
  "visibleOn": "${!isLookup}",
7868
8035
  "buttons": [
@@ -7883,8 +8050,8 @@ const getSettingListviewToolbarButtonSchema = ()=>{
7883
8050
  }
7884
8051
  };
7885
8052
 
7886
- const getDisplayAsButton = function(objectName, showDisplayAs){
7887
- let displayAs = amisLib.Router.getTabDisplayAs(objectName);
8053
+ const getDisplayAsButton = function(objectName, defaultEnableSplit){
8054
+ let displayAs = amisLib.Router.getTabDisplayAs(objectName, defaultEnableSplit);
7888
8055
  let buttons = [
7889
8056
  {
7890
8057
  "type": "button",
@@ -7907,7 +8074,7 @@ const getDisplayAsButton = function(objectName, showDisplayAs){
7907
8074
  "icon": "fa fa-table-columns",
7908
8075
  //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
7909
8076
  // "tooltip": `${i18next.t('frontend_display_as')} ${displayAsLabel}`,
7910
- "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",
7911
8078
  "align": "right",
7912
8079
  "visibleOn": "${window:innerWidth > 768 && !!!isLookup}",
7913
8080
  "buttons": [
@@ -8100,7 +8267,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8100
8267
  // //TODO: dropdown-button只支持在按钮上方配置提示,对于上方按钮的点击会有影响,为保持统一,暂时去除,等待amis优化,https://github.com/baidu/amis/issues/7330
8101
8268
  // // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8102
8269
  // "tooltipPlacement": "top",
8103
- // "className": "bg-white p-2 rounded border-gray-300 text-gray-500",
8270
+ // "className": "bg-white p-2 rounded text-gray-500",
8104
8271
  // "label": "",
8105
8272
  // "icon": "fa fa-sync",
8106
8273
  // "visibleOn": "${!showFieldsFilter}",
@@ -8124,7 +8291,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8124
8291
  // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8125
8292
  "tooltip":"",
8126
8293
  "tooltipPlacement": "top",
8127
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
8294
+ "className": "bg-white p-2 rounded text-gray-500"
8128
8295
  };
8129
8296
  }
8130
8297
  else {
@@ -8135,7 +8302,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8135
8302
  // "tooltip": i18next.t('frontend_button_reload_tooltip'),
8136
8303
  "tooltip":"",
8137
8304
  "tooltipPlacement": "top",
8138
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500"
8305
+ "className": "bg-white p-2 rounded text-gray-500"
8139
8306
  };
8140
8307
  }
8141
8308
  let toolbarFilter;
@@ -8157,7 +8324,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8157
8324
  "visibleOn": "${isFieldsFilterEmpty == false && isLookup != true}"
8158
8325
  },
8159
8326
  "align": "right",
8160
- "className": "bg-white p-2 rounded border-gray-300 text-gray-500",
8327
+ "className": "bg-white p-2 rounded text-gray-500",
8161
8328
  "onEvent": {
8162
8329
  "click": {
8163
8330
  "actions": [
@@ -8171,7 +8338,7 @@ function getObjectHeaderToolbar(mainObject, fields, formFactor, {
8171
8338
  "id": "steedos_crud_toolbar_filter"
8172
8339
  };
8173
8340
  }
8174
- let toolbarDisplayAsButton = getDisplayAsButton(mainObject?.name);
8341
+ let toolbarDisplayAsButton = getDisplayAsButton(mainObject?.name, mainObject?.enable_split);
8175
8342
  let toolbarDQuickSearchBox = getObjectHeaderQuickSearchBox(mainObject, fields, formFactor, { isLookup, keywordsSearchBoxName });
8176
8343
 
8177
8344
  // toolbars返回的数组元素不可以是空对象{},比如hiddenCount ? {} : {"type": "tpl",...},因为空对象最终还是会生成一个空的.antd-Crud-toolbar-item dom
@@ -8317,7 +8484,6 @@ async function getObjectFilter(objectSchema, fields, options) {
8317
8484
  "timeOut": 1000
8318
8485
  }
8319
8486
  });
8320
- resizeWindow();
8321
8487
  const scope = event.context.scoped;
8322
8488
  // let filterFormValues = event.data;
8323
8489
  let filterForm = SteedosUI.getClosestAmisComponentByType(scope, "form");
@@ -8484,7 +8650,7 @@ async function getObjectCRUD(objectSchema, fields, options){
8484
8650
  const bodyProps = {
8485
8651
  // toolbar: getToolbar(),
8486
8652
  // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
8487
- headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
8653
+ headerToolbarClassName: "px-4 py-2 border-b",
8488
8654
  footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
8489
8655
  ...options,
8490
8656
  disableStatistics: options.queryCount === false
@@ -8631,14 +8797,7 @@ async function getObjectCRUD(objectSchema, fields, options){
8631
8797
  headers: {
8632
8798
  Authorization: "Bearer ${context.tenantId},${context.authToken}",
8633
8799
  },
8634
- requestAdaptor: quickSaveApiRequestAdaptor,
8635
- adaptor: `
8636
- if(payload.errors){
8637
- payload.status = 2;
8638
- payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
8639
- }
8640
- return payload;
8641
- `
8800
+ requestAdaptor: quickSaveApiRequestAdaptor
8642
8801
  },
8643
8802
  // 外层data发生变化的时候, 不会重新渲染rowClassNameExpr, 所以先用css标记tr唯一标识
8644
8803
  // 使用表达式给tr添加初始选中状态
@@ -8655,6 +8814,20 @@ async function getObjectCRUD(objectSchema, fields, options){
8655
8814
  crudModeClassName = `steedos-crud-mode-${body.mode}`;
8656
8815
  }
8657
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
+
8658
8831
  if(body.columns && options.formFactor != 'SMALL'){
8659
8832
  //将_display放入crud的columns的倒数第二列中(最后一列会影响固定列),可以通过setvalue修改行内数据域的_display,而不影响上层items的_display,用于批量编辑
8660
8833
  body.columns.splice(body.columns.length -1 , 0, {name: '_display',type: 'static', width: 1, placeholder: "",id: objectSchema.name + "_display_${_index}", tpl: "${''}"});
@@ -9020,7 +9193,7 @@ const getRecordPermissions = async (objectName, recordId)=>{
9020
9193
  * @Author: baozhoutao@steedos.com
9021
9194
  * @Date: 2022-07-05 15:55:39
9022
9195
  * @LastEditors: baozhoutao@steedos.com
9023
- * @LastEditTime: 2024-01-15 10:34:46
9196
+ * @LastEditTime: 2024-01-24 10:18:17
9024
9197
  * @Description:
9025
9198
  */
9026
9199
 
@@ -9119,7 +9292,9 @@ async function getRecordDetailRelatedListSchema(objectName, recordId, relatedObj
9119
9292
  const foreign_key_value = arr[2] ? arr[1]+'.'+arr[2] : arr[1];
9120
9293
  mainRelated[arr[0]] = foreign_key_value;
9121
9294
  }
9122
- }else {
9295
+ }
9296
+ // 防止related_lists中没有相关子表,但是details中有相关子表的情况
9297
+ if(!mainRelated[relatedObjectName]){
9123
9298
  const details = _$1.union(mainObjectUiSchema.details,mainObjectUiSchema.lookup_details) || [];
9124
9299
  for (const detail of details) {
9125
9300
  const arr = detail.split(".");
@@ -9208,7 +9383,7 @@ async function getRecordDetailRelatedListSchema(objectName, recordId, relatedObj
9208
9383
  amisSchema: {
9209
9384
  type: "service",
9210
9385
  id: componentId,
9211
- 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}`,
9212
9387
  data: {
9213
9388
  relatedKey: relatedKey,
9214
9389
  listViewId: `amis-\${appId}-${relatedObjectName}-listview`,
@@ -9436,8 +9611,8 @@ async function getObjectRelatedListsMiniSchema(objectApiName){
9436
9611
  /*
9437
9612
  * @Author: baozhoutao@steedos.com
9438
9613
  * @Date: 2022-07-05 15:55:39
9439
- * @LastEditors: baozhoutao@steedos.com
9440
- * @LastEditTime: 2024-01-16 11:14:34
9614
+ * @LastEditors: liaodaxue
9615
+ * @LastEditTime: 2024-02-05 17:56:27
9441
9616
  * @Description:
9442
9617
  */
9443
9618
 
@@ -9793,6 +9968,8 @@ async function convertColumnsToTableFields(columns, uiSchema, ctx = {}) {
9793
9968
  const rfUiSchema = await getUISchema(filedInfo.reference_to);
9794
9969
  const rfFieldInfo = rfUiSchema.fields[displayName];
9795
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]);
9796
9973
  }
9797
9974
  } else {
9798
9975
  if (uiSchema.fields[column]) {
@@ -9954,7 +10131,7 @@ async function getRecordDetailSchema(objectName, appId, props = {}){
9954
10131
  };
9955
10132
  const content = {
9956
10133
  "type": "tabs",
9957
- "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",
9958
10135
  "contentClassName": "bg-none",
9959
10136
  "tabs": [
9960
10137
  detailed
@@ -10655,17 +10832,13 @@ function getReferenceToSync(field) {
10655
10832
 
10656
10833
  function getLookupSapceUserTreeSchema(isMobile){
10657
10834
  let apiAdaptor = `
10658
- // console.log("===getLookupSapceUserTreeSchema===", JSON.stringify(payload));
10659
10835
  const records = payload.data.options;
10660
- let isTreeOptionsComputed = false;
10661
- if(records.length === 1 && records[0].children){
10662
- isTreeOptionsComputed = true;
10663
- }
10664
- if(isTreeOptionsComputed){
10665
- return payload;
10666
- }
10667
10836
  const treeRecords = [];
10668
- 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
+ }
10669
10842
  if (!childrenIds) {
10670
10843
  return;
10671
10844
  }
@@ -10674,7 +10847,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10674
10847
  });
10675
10848
  _.each(children, (item) => {
10676
10849
  if (item.children) {
10677
- item.children = getChildren(records, item.children)
10850
+ item.children = getChildren(item, records, item.children)
10678
10851
  }else{
10679
10852
  item.children = [];
10680
10853
  }
@@ -10700,7 +10873,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10700
10873
 
10701
10874
  _.each(records, (record) => {
10702
10875
  if (record.noParent == 1) {
10703
- treeRecords.push(Object.assign({}, record, { children: getChildren(records, record.children) }));
10876
+ treeRecords.push(Object.assign({}, record, { children: getChildren(record, records, record.children) }));
10704
10877
  }
10705
10878
  });
10706
10879
  console.log(treeRecords)
@@ -10750,6 +10923,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10750
10923
  }
10751
10924
  },
10752
10925
  "label": "",
10926
+ "mode": "normal",
10753
10927
  "name": "organizations",
10754
10928
  "multiple": false,
10755
10929
  "joinValues": false,
@@ -10892,6 +11066,9 @@ async function lookupToAmisPicker(field, readonly, ctx){
10892
11066
  }
10893
11067
  });
10894
11068
 
11069
+ let listviewFilter = getListViewFilter(listView);
11070
+ let listviewFiltersFunction = listView && listView._filters;
11071
+
10895
11072
  let sort = "";
10896
11073
  if(listView){
10897
11074
  sort = getListViewSort(listView);
@@ -10938,7 +11115,7 @@ async function lookupToAmisPicker(field, readonly, ctx){
10938
11115
  Object.assign(api.data.$self, __changedSearchBoxValues, __changedFilterFormValues);
10939
11116
  }
10940
11117
  const selfData = JSON.parse(JSON.stringify(api.data.$self));
10941
- var filters = [];
11118
+ ${listviewFilter && !ctx.inFilterForm ? `var filters = ${JSON.stringify(listviewFilter)};` : 'var filters = [];'}
10942
11119
  var pageSize = api.data.pageSize || 10;
10943
11120
  var pageNo = api.data.pageNo || 1;
10944
11121
  var skip = (pageNo - 1) * pageSize;
@@ -11000,6 +11177,16 @@ async function lookupToAmisPicker(field, readonly, ctx){
11000
11177
  }
11001
11178
 
11002
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
+
11003
11190
  const filtersFunction = ${field.filtersFunction || field._filtersFunction};
11004
11191
 
11005
11192
  if(filtersFunction && !inFilterForm){
@@ -11087,6 +11274,16 @@ async function lookupToAmisPicker(field, readonly, ctx){
11087
11274
  });
11088
11275
  payload.data.rows = treeRecords;
11089
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
+ }
11090
11287
  return payload;
11091
11288
  `;
11092
11289
  if(field.optionsFunction || field._optionsFunction){
@@ -11118,13 +11315,15 @@ async function lookupToAmisPicker(field, readonly, ctx){
11118
11315
 
11119
11316
  pickerSchema.affixHeader = false;
11120
11317
 
11121
- var headerToolbarItems = [];
11318
+
11319
+
11320
+ pickerSchema.headerToolbar = getObjectHeaderToolbar(refObjectConfig, fieldsArr, ctx.formFactor, { isLookup: true, keywordsSearchBoxName });
11321
+
11122
11322
  if(referenceTo.objectName === "space_users" && field.reference_to_field === "user"){
11123
- headerToolbarItems = getLookupSapceUserTreeSchema(isMobile);
11323
+ pickerSchema.headerToolbar.push(getLookupSapceUserTreeSchema(isMobile));
11124
11324
  pickerSchema.className = pickerSchema.className || "" + " steedos-select-user";
11125
11325
  }
11126
-
11127
- pickerSchema.headerToolbar = getObjectHeaderToolbar(refObjectConfig, fieldsArr, ctx.formFactor, { headerToolbarItems, isLookup: true, keywordsSearchBoxName });
11326
+
11128
11327
  const isAllowCreate = refObjectConfig.permissions.allowCreate;
11129
11328
  const isCreate = ___namespace.isBoolean(field.create) ? field.create : true;
11130
11329
  // lookup字段配置过滤条件就强制不显示新建按钮
@@ -11237,8 +11436,19 @@ async function lookupToAmisPicker(field, readonly, ctx){
11237
11436
  pickerSchema.footerToolbar = ["pagination"];
11238
11437
  }
11239
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
+
11240
11449
  const data = {
11241
11450
  type: getAmisStaticFieldType('picker', readonly),
11451
+ className: ctx.className || '',
11242
11452
  modalTitle: i18next__default["default"].t('frontend_form_please_select') + " " + refObjectConfig.label,
11243
11453
  labelField: referenceTo.labelField.name,
11244
11454
  valueField: referenceTo.valueField.name,
@@ -11312,6 +11522,9 @@ async function lookupToAmisSelect(field, readonly, ctx){
11312
11522
  const refObjectConfig = referenceTo && await getUISchema(referenceTo.objectName);
11313
11523
  let listView = getLookupListView(refObjectConfig);
11314
11524
 
11525
+ let listviewFilter = getListViewFilter(listView);
11526
+ let listviewFiltersFunction = listView && listView._filters;
11527
+
11315
11528
  let sort = "";
11316
11529
  if(listView){
11317
11530
  sort = getListViewSort(listView);
@@ -11341,7 +11554,7 @@ async function lookupToAmisSelect(field, readonly, ctx){
11341
11554
  apiInfo.data['rfield'] = `\${object_name}`;
11342
11555
  // [["_id", "=", "$${field.name}._id"],"or",["name", "contains", "$term"]]
11343
11556
  apiInfo.requestAdaptor = `
11344
- var filters = [];
11557
+ ${listviewFilter && !ctx.inFilterForm ? `var filters = ${JSON.stringify(listviewFilter)};` : 'var filters = [];'}
11345
11558
  var top = 200;
11346
11559
  if(api.data.$term){
11347
11560
  filters = [["${referenceTo?.NAME_FIELD_KEY || 'name'}", "contains", api.data.$term]];
@@ -11364,6 +11577,16 @@ async function lookupToAmisSelect(field, readonly, ctx){
11364
11577
  }
11365
11578
 
11366
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
+
11367
11590
  const filtersFunction = ${field.filtersFunction || field._filtersFunction};
11368
11591
 
11369
11592
  if(filtersFunction && !inFilterForm){
@@ -11440,6 +11663,7 @@ async function lookupToAmisSelect(field, readonly, ctx){
11440
11663
  // 但是同时配置autoComplete和source会多请求一次接口
11441
11664
  // TODO:应该想办法把是否字段在子表组件内,即ctx.isInputTable,如果不在子表组件内不需要加source
11442
11665
  data.source = apiInfo;
11666
+ delete data.autoComplete;
11443
11667
  }
11444
11668
  //删除xlink:href中的rootUrl前缀,解决客户端svg为空的问题
11445
11669
  const select_menuTpl = `<span class='flex items-center mt-0.5'>
@@ -11486,7 +11710,8 @@ async function lookupToAmis(field, readonly, ctx){
11486
11710
  }
11487
11711
  // console.log(`lookupToAmis====`, field, readonly, ctx)
11488
11712
  if(readonly){
11489
- if(field.reference_to){
11713
+ if(field.reference_to && !field.isTableField){
11714
+ //isTableField只在grid字段内存在
11490
11715
  return {
11491
11716
  type: 'steedos-field',
11492
11717
  config: field,
@@ -11701,8 +11926,8 @@ if(typeof window != 'undefined'){
11701
11926
  /*
11702
11927
  * @Author: baozhoutao@steedos.com
11703
11928
  * @Date: 2023-01-13 17:27:54
11704
- * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
11705
- * @LastEditTime: 2023-08-28 17:45:38
11929
+ * @LastEditors: liaodaxue
11930
+ * @LastEditTime: 2024-02-04 17:29:54
11706
11931
  * @Description:
11707
11932
  */
11708
11933
 
@@ -11803,7 +12028,8 @@ const getHtmlFieldSchema = (field, readonly, ctx)=>{
11803
12028
  "title": "Insert",
11804
12029
  "items": "image link media addcomment pageembed codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime"
11805
12030
  }
11806
- }
12031
+ },
12032
+ "statusbar": false
11807
12033
  },
11808
12034
  "name": field.name
11809
12035
  }
@@ -12148,13 +12374,31 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12148
12374
  };
12149
12375
  break;
12150
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
+ // 日期时间字段,按日期方式展现显示控件,用户不用关心小时分钟
12151
12386
  convertData = {
12152
- type: "input-datetime-range",
12153
- inputFormat: 'YYYY-MM-DD HH:mm',
12387
+ type: "input-date-range",
12388
+ inputFormat: "YYYY-MM-DD HH:mm",
12154
12389
  format:'YYYY-MM-DDTHH:mm:ss.SSSZ',
12155
12390
  tpl: readonly ? getDateTimeTpl(field) : null,
12156
12391
  utc: true,
12157
- joinValues: false
12392
+ joinValues: false,
12393
+ "shortcuts": [
12394
+ "thismonth",
12395
+ "2monthsago",
12396
+ "3monthslater",
12397
+ "prevquarter",
12398
+ "thisquarter",
12399
+ "thisyear",
12400
+ "lastYear"
12401
+ ]
12158
12402
  };
12159
12403
  break;
12160
12404
  case 'datetime':
@@ -12205,7 +12449,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12205
12449
  convertData = {
12206
12450
  type: getAmisStaticFieldType('datetime', readonly),
12207
12451
  inputFormat: 'YYYY-MM-DD HH:mm',
12208
- format: 'YYYY-MM-DDTHH:mm:ss.SSSZ',
12452
+ format: 'YYYY-MM-DDTHH:mm:00.000Z',
12209
12453
  tpl: readonly ? getDateTimeTpl(field) : null,
12210
12454
  utc: true,
12211
12455
  };
@@ -12336,6 +12580,36 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12336
12580
  convertData = {
12337
12581
  type: 'static-text'
12338
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
+ };
12339
12613
  }
12340
12614
  break;
12341
12615
  case 'url':
@@ -12541,12 +12815,13 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12541
12815
  break;
12542
12816
  }
12543
12817
  if(!___namespace.isEmpty(convertData)){
12818
+ const className = convertData.className;
12544
12819
  if(field.is_wide || convertData.type === 'group'){
12545
- convertData.className = 'col-span-2 m-0';
12820
+ convertData.className = className ? 'col-span-2 m-0 ' + className : 'col-span-2 m-0';
12546
12821
  }else {
12547
- convertData.className = 'm-0';
12822
+ convertData.className = className ? 'm-0 ' + className : 'm-0';
12548
12823
  }
12549
- if(readonly){
12824
+ if(readonly && ctx.mode !== 'edit'){
12550
12825
  convertData.className = `${convertData.className} border-b`;
12551
12826
  }
12552
12827
  if(readonly){
@@ -12554,11 +12829,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12554
12829
  }
12555
12830
 
12556
12831
  let fieldTypeClassName = ' steedos-' + convertData.type + (readonly ? '-readonly' : '-edit');
12557
- if (convertData.className) {
12558
- convertData.className = convertData.className + fieldTypeClassName;
12559
- } else {
12560
- convertData.className = fieldTypeClassName;
12561
- }
12832
+ convertData.className = convertData.className + fieldTypeClassName;
12562
12833
 
12563
12834
  if(field.visible_on && !ctx.inFilterForm){
12564
12835
  // convertData.visibleOn = `\$${field.visible_on.substring(1, field.visible_on.length -1).replace(/formData./g, '')}`;
@@ -12641,8 +12912,9 @@ async function getFieldSearchable(perField, permissionFields, ctx){
12641
12912
  fieldNamePrefix = `${fieldNamePrefix}between__`;
12642
12913
  }
12643
12914
  if(_field.type === 'datetime'){
12644
- // 特意改为日期范围而不是日期时间范围,因为搜索时一般精确到日期就足够了,需要精确到日期时间范围需要在字段上配置amis属性来实现
12645
- _field.type = 'input-date-range';
12915
+ // 这里如果想把搜索范围展示效果改为日期范围,不可以直接改为input-date-range,因为它们规则不一样,包括时区规则和小时分秒的存值规则都不一样
12916
+ // 所以想改为展示日期范围效果,只能改input-datetime-range类型本身的属性来实现
12917
+ _field.type = 'input-datetime-range';
12646
12918
  _field.is_wide = true;
12647
12919
  fieldNamePrefix = `${fieldNamePrefix}between__`;
12648
12920
  }
@@ -12828,6 +13100,13 @@ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectio
12828
13100
  }
12829
13101
  }
12830
13102
 
13103
+ fieldSetBody.forEach((field)=>{
13104
+ //判断label是否存在,不存在时将label的空占位元素隐藏
13105
+ if(!field.label){
13106
+ field.labelClassName = "none";
13107
+ }
13108
+ });
13109
+
12831
13110
  // fieldSet 已支持显隐控制
12832
13111
  const sectionFieldsVisibleOn = ___namespace.map(___namespace.compact(___namespace.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
12833
13112
  let visible = visibleOn;
@@ -12950,12 +13229,130 @@ async function getFormBody(permissionFields, formFields, ctx){
12950
13229
  return await getSections(permissionFields, formFields, ctx);
12951
13230
  }
12952
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
+
12953
13248
  /*
12954
13249
  * @Author: 殷亮辉 yinlianghui@hotoa.com
12955
13250
  * @Date: 2023-11-15 09:50:22
12956
13251
  * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12957
- * @LastEditTime: 2024-01-18 10:29: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 转换后的子表组件字段值
12958
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 转换后的子表组件字段值
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
+ }
12959
13356
 
12960
13357
  /**
12961
13358
  * 子表组件字段值中每行数据的键值key移除指定前缀
@@ -12963,12 +13360,14 @@ async function getFormBody(permissionFields, formFields, ctx){
12963
13360
  * @param {*} fieldPrefix 字段前缀
12964
13361
  * @returns 转换后的子表组件字段值
12965
13362
  */
12966
- function getTableValueWithoutFieldPrefix(value, fieldPrefix){
13363
+ function getTableValueWithoutFieldPrefix(value, fieldPrefix) {
12967
13364
  let convertedValue = [];
12968
- (value || []).forEach((itemValue)=>{
13365
+ (value || []).forEach((itemValue) => {
12969
13366
  var newItemValue = {};
12970
- for(let n in itemValue){
12971
- newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13367
+ for (let n in itemValue) {
13368
+ if (itemValue.hasOwnProperty(n)) {
13369
+ newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13370
+ }
12972
13371
  }
12973
13372
  convertedValue.push(newItemValue);
12974
13373
  });
@@ -12979,17 +13378,21 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12979
13378
  * 子表组件字段值中每行数据的键值key补上指定前缀
12980
13379
  * @param {*} value 子表组件字段值,数组
12981
13380
  * @param {*} fieldPrefix 字段前缀
13381
+ * @param {*} primaryKey 主键字段名,主键不参与被键值key规则,需要排除,审批王amis表单也是这个规则
12982
13382
  * @returns 转换后的子表组件字段值
12983
13383
  */
12984
- function getTableValuePrependFieldPrefix(value, fieldPrefix){
13384
+ function getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey) {
12985
13385
  let convertedValue = [];
12986
- (value || []).forEach((itemValue)=>{
13386
+ (value || []).forEach((itemValue) => {
12987
13387
  var newItemValue = {};
12988
- for(let n in itemValue){
12989
- if(typeof itemValue[n] !== undefined){
13388
+ for (let n in itemValue) {
13389
+ if (itemValue.hasOwnProperty(n) && typeof itemValue[n] !== undefined && n !== primaryKey) {
12990
13390
  newItemValue[`${fieldPrefix}${n}`] = itemValue[n];
12991
13391
  }
12992
13392
  }
13393
+ if (primaryKey && itemValue[primaryKey]) {
13394
+ newItemValue[primaryKey] = itemValue[primaryKey];
13395
+ }
12993
13396
  convertedValue.push(newItemValue);
12994
13397
  });
12995
13398
  return convertedValue;
@@ -13001,7 +13404,7 @@ function getTableValuePrependFieldPrefix(value, fieldPrefix){
13001
13404
  * @param {*} fieldPrefix 字段前缀
13002
13405
  * @returns 转换后的子表组件字段值
13003
13406
  */
13004
- function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
13407
+ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix) {
13005
13408
  return (fields || []).map((item) => {
13006
13409
  const newItem = _$1.clone(item);//这里不clone的话,会造成子表组件重新render,从而审批王那边点开子表行编辑窗口时报错
13007
13410
  newItem.name = newItem.name.replace(new RegExp(`^${fieldPrefix}`), "");
@@ -13014,7 +13417,12 @@ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
13014
13417
  * @param {*} mode edit/new/readonly
13015
13418
  */
13016
13419
  function getFormFields(props, mode = "edit") {
13017
- 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) {
13018
13426
  let formItem = {
13019
13427
  "type": "steedos-field",
13020
13428
  "name": item.name,
@@ -13034,6 +13442,7 @@ function getInputTableCell(field, showAsInlineEditMode) {
13034
13442
  name: field.name,
13035
13443
  quickEdit: {
13036
13444
  "type": "steedos-field",
13445
+ "mode": "inline",
13037
13446
  "config": Object.assign({}, field, {
13038
13447
  label: false
13039
13448
  })
@@ -13086,7 +13495,12 @@ async function getInputTableColumns(props) {
13086
13495
  let inlineEditMode = props.inlineEditMode;
13087
13496
  let showAsInlineEditMode = inlineEditMode && props.editable;
13088
13497
  // 实测过,直接不生成对应的隐藏column并不会对input-table值造成丢失问题,隐藏的列字段值能正常维护
13089
- let fields = props.fields;
13498
+
13499
+ let fieldPrefix = props.fieldPrefix;
13500
+ let fields = props.fields || [];
13501
+ if (fieldPrefix) {
13502
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13503
+ }
13090
13504
  if (columns && columns.length) {
13091
13505
  return columns.map(function (column) {
13092
13506
  let field, extendColumnProps = {};
@@ -13108,8 +13522,26 @@ async function getInputTableColumns(props) {
13108
13522
  }
13109
13523
  }
13110
13524
  if (field) {
13111
- let tableCell = getInputTableCell(field, showAsInlineEditMode);
13112
- 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});
13113
13545
  }
13114
13546
  else {
13115
13547
  return column;
@@ -13119,6 +13551,7 @@ async function getInputTableColumns(props) {
13119
13551
  else {
13120
13552
  return fields.map(function (field) {
13121
13553
  let tableCell = getInputTableCell(field, showAsInlineEditMode);
13554
+ tableCell.className = " whitespace-nowrap ";
13122
13555
  return tableCell;
13123
13556
  }) || [];
13124
13557
  }
@@ -13131,7 +13564,7 @@ async function getInputTableColumns(props) {
13131
13564
  */
13132
13565
  function getFormPagination(props, mode) {
13133
13566
  let showPagination = true;
13134
- if(mode === "new" && !!!props.editable){
13567
+ if (mode === "new" && !!!props.editable) {
13135
13568
  //不允许编辑只允许新建时不应该让用户操作翻页
13136
13569
  showPagination = false;
13137
13570
  }
@@ -13147,35 +13580,41 @@ function getFormPagination(props, mode) {
13147
13580
  let __formId = "${formId}";
13148
13581
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13149
13582
  let pageChangeDirection = context.props.pageChangeDirection;
13583
+ let mode = "${mode}";
13150
13584
  // event.data中的index和__page分别表示当前要把表单数据提交到的行索引和用于标定下一页页码的当前页页码
13151
13585
  // 一般来说__page = index + 1,但是可以让event.data中传入__page和index值不是这种联系。
13152
13586
  // 比如__page设置为3,index设置为0表示把当前表单数据提交到第一页,但是跳转到第4页,弹出的表单中底下的新增和复制按钮依赖了此功能
13153
13587
  // let currentPage = currentIndex + 1;
13154
13588
  let currentPage = event.data.__page;
13155
13589
  let currentIndex = event.data.index;
13156
- // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13157
- let currentFormValues = scope.getComponentById(__formId).getValues();
13158
- var parent = event.data.parent;
13159
- var __parentIndex = event.data.__parentIndex;
13160
- if(parent){
13161
- fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13162
- // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13163
- fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13164
- children: fieldValue[__parentIndex].children,
13165
- __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
+ }
13166
13616
  });
13167
13617
  }
13168
- else{
13169
- fieldValue[currentIndex] = currentFormValues;
13170
- }
13171
- // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13172
- doAction({
13173
- "componentId": "${props.id}",
13174
- "actionType": "setValue",
13175
- "args": {
13176
- "value": fieldValue
13177
- }
13178
- });
13179
13618
 
13180
13619
  // 以下是翻页逻辑,翻到下一页并把下一页内容显示到表单上
13181
13620
  let targetPage;
@@ -13224,9 +13663,14 @@ function getFormPagination(props, mode) {
13224
13663
  "onEvent": {
13225
13664
  "click": {
13226
13665
  "actions": [
13666
+ {
13667
+ "actionType": "validate",
13668
+ "componentId": formId
13669
+ },
13227
13670
  {
13228
13671
  "actionType": "custom",
13229
- "script": onPageChangeScript
13672
+ "script": onPageChangeScript,
13673
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13230
13674
  }
13231
13675
  ]
13232
13676
  }
@@ -13235,7 +13679,7 @@ function getFormPagination(props, mode) {
13235
13679
  {
13236
13680
  "type": "tpl",
13237
13681
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13238
- "tpl": "${__page}/${__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length}"
13682
+ "tpl": "${__page}/${__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length}"
13239
13683
  },
13240
13684
  {
13241
13685
  "type": "button",
@@ -13245,15 +13689,20 @@ function getFormPagination(props, mode) {
13245
13689
  "pageChangeDirection": "next",
13246
13690
  // "disabledOn": showPagination ? "${__page >= __tableItems.length}" : "true",
13247
13691
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13248
- "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",
13249
13693
  "size": "sm",
13250
13694
  "id": buttonNextId,
13251
13695
  "onEvent": {
13252
13696
  "click": {
13253
13697
  "actions": [
13698
+ {
13699
+ "actionType": "validate",
13700
+ "componentId": formId
13701
+ },
13254
13702
  {
13255
13703
  "actionType": "custom",
13256
- "script": onPageChangeScript
13704
+ "script": onPageChangeScript,
13705
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13257
13706
  }
13258
13707
  ]
13259
13708
  }
@@ -13274,6 +13723,7 @@ function getFormPaginationWrapper(props, form, mode) {
13274
13723
  // console.log("==getFormPaginationWrapper===", props, mode);
13275
13724
  let serviceId = getComponentId("form_pagination", props.id);
13276
13725
  let tableServiceId = getComponentId("table_service", props.id);
13726
+ let primaryKey = getTablePrimaryKey(props);
13277
13727
  let innerForm = Object.assign({}, form, {
13278
13728
  "data": {
13279
13729
  // 这里加__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
@@ -13301,7 +13751,6 @@ function getFormPaginationWrapper(props, form, mode) {
13301
13751
  }
13302
13752
  ];
13303
13753
  let onServiceInitedScript = `
13304
-
13305
13754
  // 以下脚本解决了有时弹出编辑表单时,表单中的值比最后一次编辑保存的值会延迟一拍。
13306
13755
  // 比如:inlineEditMode模式时,用户在表格单元格中直接修改数据,然后弹出的表单form中并没有包含单元格中修改的内容
13307
13756
  // 另外有的地方在非inlineEditMode模式时也会有这种延迟一拍问题,比如对象字段中下拉框类型字段的”选择项“属性
@@ -13315,13 +13764,13 @@ function getFormPaginationWrapper(props, form, mode) {
13315
13764
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13316
13765
  // 这里如果不.clone的话,在弹出窗口中显示的子表组件,添加行后点窗口的取消按钮关闭窗口后无法把之前的操作还原,即把之前添加的行自动移除
13317
13766
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"] || []);
13318
- let fieldPrefix = "${props.fieldPrefix}";
13767
+ let fieldPrefix = "${props.fieldPrefix || ''}";
13319
13768
  if(fieldPrefix){
13320
13769
  let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
13321
13770
  lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
13322
13771
  }
13323
13772
  //不可以直接像event.data.__tableItems = lastestFieldValue; 这样整个赋值,否则作用域会断
13324
- let mode = "${mode}";
13773
+ let mode = "${mode || ''}";
13325
13774
  if(mode === "new"){
13326
13775
  // 点击子表组件底部新增按钮时新增一条空白行并自动翻页到新增行
13327
13776
  // 注意点击弹出的子表行详细表单中的新增按钮不会进此service init事件函数中
@@ -13347,10 +13796,20 @@ function getFormPaginationWrapper(props, form, mode) {
13347
13796
  var fieldValue = event.data.__tableItems;
13348
13797
  if(parent){
13349
13798
  // 如果是子行,即在节点嵌套情况下,当前节点如果是children属性下的子节点时,则算出其所属父行的索引值
13350
- var primaryKey = "${props.primaryKey}";
13799
+ var primaryKey = "${primaryKey}";
13351
13800
  event.data.__parentIndex = _.findIndex(fieldValue, function(item){
13352
13801
  return item[primaryKey] == parent[primaryKey];
13353
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
+ }
13354
13813
  }
13355
13814
  `;
13356
13815
  let schema = {
@@ -13399,6 +13858,7 @@ function getFormPaginationWrapper(props, form, mode) {
13399
13858
  async function getForm(props, mode = "edit", formId) {
13400
13859
  let formFields = getFormFields(props, mode);
13401
13860
  let body = await getFormBody(null, formFields);
13861
+ let primaryKey = getTablePrimaryKey(props);
13402
13862
  if (!formId) {
13403
13863
  formId = getComponentId("form", props.id);
13404
13864
  }
@@ -13417,6 +13877,18 @@ async function getForm(props, mode = "edit", formId) {
13417
13877
  // 新增行弹出编辑行表单,在弹出之前已经不用先增加一行,因为在翻页service初始化的时候会判断mode为new时自动新增一行
13418
13878
  let onEditItemSubmitScript = `
13419
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);
13420
13892
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13421
13893
  //这里加__super.__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
13422
13894
  // 比如“对象字段”对象options字段是一个子表字段,但是主表(即“对象字段”对象)中正好有一个名为index的字段
@@ -13425,6 +13897,8 @@ async function getForm(props, mode = "edit", formId) {
13425
13897
  var currentFormValues = JSON.parse(JSON.stringify(event.data));
13426
13898
  var parent = event.data.__super.__super.parent;
13427
13899
  var __parentIndex = event.data.__super.__super.__parentIndex;
13900
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13901
+ var primaryKey = "${primaryKey}";
13428
13902
  if(parent){
13429
13903
  fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13430
13904
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13434,6 +13908,8 @@ async function getForm(props, mode = "edit", formId) {
13434
13908
  });
13435
13909
  }
13436
13910
  else{
13911
+ // 这里currentFormValues中如果没有primaryKey字段值不用处理,因为组件的pipeIn/pipeOut中会为每行自动生成
13912
+ // 也不用担心复制行时_id会重复,因为点击复制按钮时已经处理过了
13437
13913
  fieldValue[currentIndex] = currentFormValues;
13438
13914
  }
13439
13915
  doAction({
@@ -13531,13 +14007,14 @@ async function getForm(props, mode = "edit", formId) {
13531
14007
  */
13532
14008
  async function getButtonActions(props, mode) {
13533
14009
  let actions = [];
14010
+ let primaryKey = getTablePrimaryKey(props);
13534
14011
  let formId = getComponentId("form", props.id);
13535
14012
  let dialogId = getComponentId("dialog", props.id);
13536
14013
  let buttonNextId = getComponentId("button_next", props.id);
13537
14014
  let formPaginationId = getComponentId("form_pagination", props.id);
13538
14015
  let parentFormData = "${__super.__super.__super.__super || {}}";
13539
14016
  let amisVersion = getComparableAmisVersion();
13540
- if(amisVersion < 3.6){
14017
+ if (amisVersion < 3.6) {
13541
14018
  parentFormData = "${__super.__super || {}}";
13542
14019
  }
13543
14020
  if (mode == "new" || mode == "edit") {
@@ -13573,13 +14050,35 @@ async function getButtonActions(props, mode) {
13573
14050
  // };
13574
14051
  let onSaveAndNewItemScript = `
13575
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);
13576
14065
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13577
14066
  // 新建一条空白行并保存到子表组件
13578
14067
  var parent = event.data.__super.parent;
13579
- var primaryKey = "${props.primaryKey}";
14068
+ var primaryKey = "${primaryKey}";
13580
14069
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13581
14070
  return item[primaryKey] == parent[primaryKey];
13582
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
+ }
13583
14082
  if(parent){
13584
14083
  fieldValue[__parentIndex].children.push({});
13585
14084
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13613,14 +14112,42 @@ async function getButtonActions(props, mode) {
13613
14112
  let __formId = "${formId}";
13614
14113
  // let newItem = JSON.parse(JSON.stringify(event.data));
13615
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);
13616
14128
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13617
14129
  // 复制当前页数据到新建行并保存到子表组件
13618
14130
  // fieldValue.push(newItem);
13619
14131
  var parent = event.data.__super.parent;
13620
- var primaryKey = "${props.primaryKey}";
14132
+ var primaryKey = "${primaryKey}";
13621
14133
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13622
14134
  return item[primaryKey] == parent[primaryKey];
13623
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
+ }
13624
14151
  if(parent){
13625
14152
  fieldValue[__parentIndex].children.push(newItem);
13626
14153
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13651,13 +14178,13 @@ async function getButtonActions(props, mode) {
13651
14178
  `;
13652
14179
  let dialogButtons = [
13653
14180
  {
13654
- "type": "button",
13655
- "label": "完成",
13656
- "actionType": "confirm",
13657
- "level": "primary"
14181
+ "type": "button",
14182
+ "label": "完成",
14183
+ "actionType": "confirm",
14184
+ "level": "primary"
13658
14185
  }
13659
14186
  ];
13660
- if(props.addable){
14187
+ if (props.addable) {
13661
14188
  // 有新增行权限时额外添加新增和复制按钮
13662
14189
  dialogButtons = [
13663
14190
  {
@@ -13667,9 +14194,14 @@ async function getButtonActions(props, mode) {
13667
14194
  "onEvent": {
13668
14195
  "click": {
13669
14196
  "actions": [
14197
+ {
14198
+ "actionType": "validate",
14199
+ "componentId": formId
14200
+ },
13670
14201
  {
13671
14202
  "actionType": "custom",
13672
- "script": onSaveAndNewItemScript
14203
+ "script": onSaveAndNewItemScript,
14204
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13673
14205
  }
13674
14206
  ]
13675
14207
  }
@@ -13682,9 +14214,14 @@ async function getButtonActions(props, mode) {
13682
14214
  "onEvent": {
13683
14215
  "click": {
13684
14216
  "actions": [
14217
+ {
14218
+ "actionType": "validate",
14219
+ "componentId": formId
14220
+ },
13685
14221
  {
13686
14222
  "actionType": "custom",
13687
- "script": onSaveAndCopyItemScript
14223
+ "script": onSaveAndCopyItemScript,
14224
+ "expression": "${!!!event.data.validateResult.error}" //触发表单校验结果会存入validateResult,amis 3.2不支持,高版本比如 3.5.3支持
13688
14225
  }
13689
14226
  ]
13690
14227
  }
@@ -13730,7 +14267,7 @@ async function getButtonActions(props, mode) {
13730
14267
  // 在节点嵌套情况下,当前节点正好是带children属性的节点的话,这里弹出的dialog映射到的会是children数组,这是amis目前的规则,
13731
14268
  // 所以这里加判断有children时,用__super.__super让映射到正确的作用域层,如果不加,则__tableItems取到的会是children数组,而不是整个子表组件的值
13732
14269
  "__tableItems": `\${((children ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13733
- },
14270
+ },
13734
14271
  "actions": dialogButtons,
13735
14272
  "onEvent": {
13736
14273
  "confirm": {
@@ -13828,7 +14365,10 @@ async function getButtonActions(props, mode) {
13828
14365
  // 为了解决"弹出的dialog窗口中子表组件会影响页面布局界面中父作用域字段值",比如设计字段布局微页面中的设置分组功能,弹出的就是子表dialog
13829
14366
  // 所以这里使用json|toJson转一次,断掉event.data.__tableItems与上层任用域中props.name的联系
13830
14367
  // "__tableItems": `\${${props.name}|json|toJson}`
13831
- "__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}`
13832
14372
  },
13833
14373
  }
13834
14374
  }
@@ -13844,13 +14384,24 @@ async function getButtonActions(props, mode) {
13844
14384
  let wrapperServiceData = wrapperService.getData();
13845
14385
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13846
14386
  // 这里_.clone是因为字段设计布局设置分组这种弹出窗口中的子表组件,直接删除后,点取消无法还原
14387
+ // 也因为这里clone没有直接删除,所以弹出编辑表单提交事件中event.data.__tableItems中取到的值会有被删除的行数据为undefined
13847
14388
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"]);
13848
14389
  var currentIndex = event.data.index;
13849
14390
  var parent = event.data.__super.parent;
13850
- var primaryKey = "${props.primaryKey}";
14391
+ var primaryKey = "${primaryKey}";
13851
14392
  var __parentIndex = parent && _.findIndex(lastestFieldValue, function(item){
13852
14393
  return item[primaryKey] == parent[primaryKey];
13853
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
+ }
13854
14405
  if(parent){
13855
14406
  lastestFieldValue[__parentIndex].children.splice(currentIndex, 1);
13856
14407
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13862,6 +14413,11 @@ async function getButtonActions(props, mode) {
13862
14413
  else{
13863
14414
  lastestFieldValue.splice(currentIndex, 1);
13864
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
+ }
13865
14421
  doAction({
13866
14422
  "componentId": "${props.id}",
13867
14423
  "actionType": "setValue",
@@ -13931,45 +14487,77 @@ async function getButtonView(props) {
13931
14487
 
13932
14488
  async function getButtonDelete(props) {
13933
14489
  return {
13934
- "type": "button",
13935
- "label": "",
13936
- "icon": "fa fa-trash-alt",//不可以用fa-trash-o,因为设计字段布局界面中弹出的设置分组列表中显示不了这个图标
14490
+ "type": "dropdown-button",
13937
14491
  "level": "link",
13938
- "onEvent": {
13939
- "click": {
13940
- "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
+ ]
13941
14529
  }
13942
- }
13943
- };
14530
+ ]
14531
+ }
13944
14532
  }
13945
14533
 
14534
+
13946
14535
  const getAmisInputTableSchema = async (props) => {
13947
14536
  if (!props.id) {
13948
14537
  props.id = "steedos_input_table_" + props.name + "_" + Math.random().toString(36).substr(2, 9);
13949
14538
  }
13950
- if (!props.primaryKey) {
13951
- props.primaryKey = "_id";
13952
- }
14539
+ let primaryKey = getTablePrimaryKey(props);
13953
14540
  let showOperation = props.showOperation;
13954
- if(showOperation !== false){
14541
+ if (showOperation !== false) {
13955
14542
  showOperation = true;
13956
14543
  }
13957
- // props.fieldPrefix = "project_milestone_";
13958
- if (props.fieldPrefix) {
13959
- 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);
13960
14548
  }
13961
14549
  let serviceId = getComponentId("table_service", props.id);
13962
14550
  let buttonsForColumnOperations = [];
13963
14551
  let inlineEditMode = props.inlineEditMode;
13964
14552
  let showAsInlineEditMode = inlineEditMode && props.editable;
13965
- if(showOperation){
14553
+ if (showOperation) {
13966
14554
  if (props.editable) {
13967
14555
  let showEditButton = true;
13968
14556
  if (showAsInlineEditMode) {
13969
14557
  // 始终显示弹出子表表单按钮,如果需要判断只在有列被隐藏时才需要显示弹出表单按钮放开下面的if逻辑就好
13970
14558
  showEditButton = true;
13971
14559
  // // inline edit模式下只在有列被隐藏时才需要显示编辑按钮
13972
- // 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) {
13973
14561
  // showEditButton = true;
13974
14562
  // }
13975
14563
  // else {
@@ -13984,7 +14572,7 @@ const getAmisInputTableSchema = async (props) => {
13984
14572
  }
13985
14573
  else {
13986
14574
  // 只读时显示查看按钮
13987
- // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断: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)
13988
14576
  let buttonViewSchema = await getButtonView(props);
13989
14577
  buttonsForColumnOperations.push(buttonViewSchema);
13990
14578
  }
@@ -13993,10 +14581,10 @@ const getAmisInputTableSchema = async (props) => {
13993
14581
  buttonsForColumnOperations.push(buttonDeleteSchema);
13994
14582
  }
13995
14583
  }
13996
- let amis = props["input-table"] || props.amis;//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
14584
+ let amis = props["input-table"] || props.amis || {};//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
13997
14585
  let inputTableSchema = {
13998
14586
  "type": "input-table",
13999
- "label": props.label,
14587
+ "mode": "normal",
14000
14588
  "name": props.name,
14001
14589
  //不可以addable/editable/removable设置为true,因为会在原生的操作列显示操作按钮图标,此开关实测只控制这个按钮显示不会影响功能
14002
14590
  // "addable": props.addable,
@@ -14012,36 +14600,53 @@ const getAmisInputTableSchema = async (props) => {
14012
14600
  "showTableAddBtn": false,
14013
14601
  "showFooterAddBtn": false,
14014
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
+ },
14015
14621
  "pipeOut": (value, data) => {
14016
- value = (value || []).map(function(item){
14622
+ value = (value || []).map(function (item) {
14017
14623
  delete item.__fix_rerender_after_children_modified_tag;
14018
14624
  return item;
14019
14625
  });
14020
- if(props.fieldPrefix){
14021
- value = getTableValuePrependFieldPrefix(value, props.fieldPrefix);
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);
14022
14634
  }
14023
- if(amis.pipeOut){
14024
- if(typeof amis.pipeOut === 'function'){
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') {
14025
14644
  return amis.pipeOut(value, data);
14026
14645
  }
14027
14646
  }
14028
14647
  return value;
14029
14648
  }
14030
14649
  };
14031
- if(amis.pipeIn){
14032
- inputTableSchema.pipeIn = amis.pipeIn;
14033
- }
14034
- if(props.fieldPrefix){
14035
- inputTableSchema.pipeIn = (value, data) => {
14036
- value = getTableValueWithoutFieldPrefix(value, props.fieldPrefix);
14037
- if(amis.pipeIn){
14038
- if(typeof amis.pipeIn === 'function'){
14039
- return amis.pipeIn(value, data);
14040
- }
14041
- }
14042
- return value;
14043
- };
14044
- }
14045
14650
  if (buttonsForColumnOperations.length) {
14046
14651
  inputTableSchema.columns.push({
14047
14652
  "name": "__op__",
@@ -14050,9 +14655,10 @@ const getAmisInputTableSchema = async (props) => {
14050
14655
  "width": buttonsForColumnOperations.length > 1 ? "60px" : "20px"
14051
14656
  });
14052
14657
  }
14053
- if (showAsInlineEditMode) {
14054
- inputTableSchema.needConfirm = false;
14055
- }
14658
+ // if (showAsInlineEditMode) {
14659
+ // // 因为要支持不同的列上配置inlineEditMode属性,所有不可以把整个子表组件都设置为inlineEditMode
14660
+ // inputTableSchema.needConfirm = false;
14661
+ // }
14056
14662
  if (amis) {
14057
14663
  // 支持配置amis属性重写或添加最终生成的input-table中任何属性。
14058
14664
  delete amis.id;//如果steedos-input-table组件配置了amis.id属性,会造成新建编辑行功能不生效
@@ -14060,7 +14666,7 @@ const getAmisInputTableSchema = async (props) => {
14060
14666
  delete amis.pipeOut;//该属性在上面合并过了
14061
14667
  Object.assign(inputTableSchema, amis);
14062
14668
  }
14063
- const isAnyFieldHasDependOn = (props.fields || []).find(function (item) {
14669
+ const isAnyFieldHasDependOn = (fields || []).find(function (item) {
14064
14670
  return item.depend_on;
14065
14671
  });
14066
14672
  if (isAnyFieldHasDependOn) {
@@ -14093,11 +14699,31 @@ const getAmisInputTableSchema = async (props) => {
14093
14699
  "body": headerToolbar
14094
14700
  });
14095
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
+
14096
14713
  let schema = {
14097
- "type": "service",
14098
- "body": schemaBody,
14099
- "className": props.className,
14100
- "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
14101
14727
  };
14102
14728
  // console.log("===schema===", schema);
14103
14729
  return schema;