@steedos-widgets/amis-lib 3.6.2-beta.10 → 3.6.2-beta.12

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.esm.js CHANGED
@@ -354,6 +354,9 @@ const Router = {
354
354
  if(uiSchema.enable_split){
355
355
  defaultDisplay = "split";
356
356
  }
357
+ if(window.innerWidth <= 768){
358
+ return "grid";
359
+ }
357
360
  return value ? value : defaultDisplay;
358
361
  },
359
362
 
@@ -1281,6 +1284,7 @@ var frontend_notifications$1 = "Notifications";
1281
1284
  var frontend_notifications_allread$1 = "Mark all as read";
1282
1285
  var frontend_notifications_allread_message$1 = "All marked as read";
1283
1286
  var frontend_profile$1 = "Profile";
1287
+ var switch_space$1 = "Switch Space";
1284
1288
  var frontend_about$1 = "About";
1285
1289
  var frontend_log_out$1 = "Log out";
1286
1290
  var frontend_listview_warning_start$1 = "The current ";
@@ -1368,6 +1372,7 @@ var en_us = {
1368
1372
  frontend_notifications_allread: frontend_notifications_allread$1,
1369
1373
  frontend_notifications_allread_message: frontend_notifications_allread_message$1,
1370
1374
  frontend_profile: frontend_profile$1,
1375
+ switch_space: switch_space$1,
1371
1376
  frontend_about: frontend_about$1,
1372
1377
  frontend_log_out: frontend_log_out$1,
1373
1378
  frontend_listview_warning_start: frontend_listview_warning_start$1,
@@ -1457,6 +1462,7 @@ var frontend_notifications = "通知";
1457
1462
  var frontend_notifications_allread = "全部标记为已读";
1458
1463
  var frontend_notifications_allread_message = "已全部标记为已读";
1459
1464
  var frontend_profile = "个人资料";
1465
+ var switch_space = "切换工作区";
1460
1466
  var frontend_about = "关于";
1461
1467
  var frontend_log_out = "注销";
1462
1468
  var frontend_listview_warning_start = "当前";
@@ -1545,6 +1551,7 @@ var zh_cn = {
1545
1551
  frontend_notifications_allread: frontend_notifications_allread,
1546
1552
  frontend_notifications_allread_message: frontend_notifications_allread_message,
1547
1553
  frontend_profile: frontend_profile,
1554
+ switch_space: switch_space,
1548
1555
  frontend_about: frontend_about,
1549
1556
  frontend_log_out: frontend_log_out,
1550
1557
  frontend_listview_warning_start: frontend_listview_warning_start,
@@ -2033,7 +2040,7 @@ async function getQuickEditSchema(field, options){
2033
2040
  }
2034
2041
 
2035
2042
  function getFieldWidth(width){
2036
- const defaultWidth = "unset";//用于使table内的td标签下生成div,实现将快速编辑按钮固定在右侧的效果,并不是为了unset效果
2043
+ const defaultWidth = null;
2037
2044
  if(typeof width == 'string'){
2038
2045
  if(isNaN(width)){
2039
2046
  return width || defaultWidth;
@@ -2063,14 +2070,14 @@ async function getTableColumns(fields, options){
2063
2070
  //增加quickEdit属性,实现快速编辑
2064
2071
  const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
2065
2072
  let className = "";
2066
- if(field.wrap != true){
2067
- if(field.wrap != false && field.is_wide){
2068
- className += " break-words ";
2069
- }else {
2073
+ if(/Safari/.test(navigator.userAgent)){
2074
+ className += " whitespace-nowrap ";
2075
+ }else {
2076
+ if(field.wrap != true){
2070
2077
  className += " whitespace-nowrap ";
2078
+ }else {
2079
+ className += " break-words ";
2071
2080
  }
2072
- }else {
2073
- className += " break-words ";
2074
2081
  }
2075
2082
  let columnItem;
2076
2083
  if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
@@ -10628,17 +10635,13 @@ function getReferenceToSync(field) {
10628
10635
 
10629
10636
  function getLookupSapceUserTreeSchema(isMobile){
10630
10637
  let apiAdaptor = `
10631
- // console.log("===getLookupSapceUserTreeSchema===", JSON.stringify(payload));
10632
10638
  const records = payload.data.options;
10633
- let isTreeOptionsComputed = false;
10634
- if(records.length === 1 && records[0].children){
10635
- isTreeOptionsComputed = true;
10636
- }
10637
- if(isTreeOptionsComputed){
10638
- return payload;
10639
- }
10640
10639
  const treeRecords = [];
10641
- const getChildren = (records, childrenIds) => {
10640
+ const getChildren = (currentRecord, records, childrenIds) => {
10641
+ if (currentRecord.children && typeof currentRecord.children[0] === "object") {
10642
+ // 考虑api配置了cache缓存的话,不会请求接口但是会重新进这个接收适配器脚本且payload.data.options返回的会是上一次计算结果,这里直接返回计算过的children
10643
+ return currentRecord.children;
10644
+ }
10642
10645
  if (!childrenIds) {
10643
10646
  return;
10644
10647
  }
@@ -10647,7 +10650,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10647
10650
  });
10648
10651
  _.each(children, (item) => {
10649
10652
  if (item.children) {
10650
- item.children = getChildren(records, item.children)
10653
+ item.children = getChildren(item, records, item.children)
10651
10654
  }else{
10652
10655
  item.children = [];
10653
10656
  }
@@ -10673,7 +10676,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10673
10676
 
10674
10677
  _.each(records, (record) => {
10675
10678
  if (record.noParent == 1) {
10676
- treeRecords.push(Object.assign({}, record, { children: getChildren(records, record.children) }));
10679
+ treeRecords.push(Object.assign({}, record, { children: getChildren(record, records, record.children) }));
10677
10680
  }
10678
10681
  });
10679
10682
  console.log(treeRecords)
@@ -12519,7 +12522,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12519
12522
  }else {
12520
12523
  convertData.className = 'm-0';
12521
12524
  }
12522
- if(readonly){
12525
+ if(readonly && ctx.mode !== 'edit'){
12523
12526
  convertData.className = `${convertData.className} border-b`;
12524
12527
  }
12525
12528
  if(readonly){
@@ -12801,6 +12804,13 @@ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectio
12801
12804
  }
12802
12805
  }
12803
12806
 
12807
+ fieldSetBody.forEach((field)=>{
12808
+ //判断label是否存在,不存在时将label的空占位元素隐藏
12809
+ if(!field.label){
12810
+ field.labelClassName = "none";
12811
+ }
12812
+ });
12813
+
12804
12814
  // fieldSet 已支持显隐控制
12805
12815
  const sectionFieldsVisibleOn = _$1.map(_$1.compact(_$1.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
12806
12816
  let visible = visibleOn;
@@ -12923,13 +12933,83 @@ async function getFormBody(permissionFields, formFields, ctx){
12923
12933
  return await getSections(permissionFields, formFields, ctx);
12924
12934
  }
12925
12935
 
12936
+ /*
12937
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
12938
+ * @Date: 2024-01-18 15:12:41
12939
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12940
+ * @LastEditTime: 2024-01-18 15:12:49
12941
+ */
12942
+ /**
12943
+ * 生成符合标准uuid格式的36位满足唯一性的随机串
12944
+ * @returns uuid
12945
+ */
12946
+ function uuidv4() {
12947
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
12948
+ (c ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
12949
+ );
12950
+ }
12951
+
12926
12952
  /*
12927
12953
  * @Author: 殷亮辉 yinlianghui@hotoa.com
12928
12954
  * @Date: 2023-11-15 09:50:22
12929
12955
  * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12930
- * @LastEditTime: 2024-01-18 10:29:57
12956
+ * @LastEditTime: 2024-01-22 15:59:32
12931
12957
  */
12932
12958
 
12959
+ function getTablePrimaryKey(props){
12960
+ return props.primaryKey || "_id";
12961
+ }
12962
+
12963
+ /**
12964
+ * 子表组件字段值中每行数据的补上唯一标识字段值,其值为随机uuid
12965
+ * @param {*} value 子表组件字段值,数组
12966
+ * @param {*} primaryKey 主键字段名,一般为_id
12967
+ * @returns 转换后的子表组件字段值
12968
+ */
12969
+ function getTableValueWithPrimaryKeyValue(value, primaryKey){
12970
+ if(!primaryKey){
12971
+ return value;
12972
+ }
12973
+ return (value || []).map((itemValue)=>{
12974
+ //这里不clone的话,会造成在pipeIn函数执行该函数后像pipeOut一样最终输出到表单项中,即库里把primaryKey字段值保存了
12975
+ const newItemValue = clone(itemValue);
12976
+ if(newItemValue[primaryKey]){
12977
+ if(newItemValue.children){
12978
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
12979
+ }
12980
+ return newItemValue;
12981
+ }
12982
+ else {
12983
+ newItemValue[primaryKey] = uuidv4();
12984
+ if(newItemValue.children){
12985
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
12986
+ }
12987
+ return newItemValue;
12988
+ }
12989
+ });
12990
+ }
12991
+
12992
+ /**
12993
+ * 子表组件字段值中每行数据的移除唯一标识字段值,因为该字段值一般只作临时标记,不存库
12994
+ * @param {*} value 子表组件字段值,数组
12995
+ * @param {*} primaryKey 主键字段名,一般为_id
12996
+ * @returns 转换后的子表组件字段值
12997
+ */
12998
+ function getTableValueWithoutPrimaryKeyValue(value, primaryKey){
12999
+ if(!primaryKey){
13000
+ return value;
13001
+ }
13002
+ return (value || []).map((itemValue)=>{
13003
+ //这里clone只是为了保险,不是必须的,每次修改子表数据是否都会生成新的primaryKey字段值是由pipeOut中识别autoGeneratePrimaryKeyValue决定的,跟这里没关系
13004
+ const newItemValue = clone(itemValue);
13005
+ if(newItemValue.children){
13006
+ newItemValue.children = getTableValueWithoutPrimaryKeyValue(newItemValue.children, primaryKey);
13007
+ }
13008
+ delete newItemValue[primaryKey];
13009
+ return newItemValue;
13010
+ });
13011
+ }
13012
+
12933
13013
  /**
12934
13014
  * 子表组件字段值中每行数据的键值key移除指定前缀
12935
13015
  * @param {*} value 子表组件字段值,数组
@@ -12941,7 +13021,9 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12941
13021
  (value || []).forEach((itemValue)=>{
12942
13022
  var newItemValue = {};
12943
13023
  for(let n in itemValue){
12944
- newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13024
+ if(itemValue.hasOwnProperty(n)){
13025
+ newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13026
+ }
12945
13027
  }
12946
13028
  convertedValue.push(newItemValue);
12947
13029
  });
@@ -12954,15 +13036,18 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12954
13036
  * @param {*} fieldPrefix 字段前缀
12955
13037
  * @returns 转换后的子表组件字段值
12956
13038
  */
12957
- function getTableValuePrependFieldPrefix(value, fieldPrefix){
13039
+ function getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey){
12958
13040
  let convertedValue = [];
12959
13041
  (value || []).forEach((itemValue)=>{
12960
13042
  var newItemValue = {};
12961
13043
  for(let n in itemValue){
12962
- if(typeof itemValue[n] !== undefined){
13044
+ if(itemValue.hasOwnProperty(n) && typeof itemValue[n] !== undefined && n !== primaryKey){
12963
13045
  newItemValue[`${fieldPrefix}${n}`] = itemValue[n];
12964
13046
  }
12965
13047
  }
13048
+ if(primaryKey && itemValue[primaryKey]){
13049
+ newItemValue[primaryKey] = itemValue[primaryKey];
13050
+ }
12966
13051
  convertedValue.push(newItemValue);
12967
13052
  });
12968
13053
  return convertedValue;
@@ -12987,7 +13072,12 @@ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
12987
13072
  * @param {*} mode edit/new/readonly
12988
13073
  */
12989
13074
  function getFormFields(props, mode = "edit") {
12990
- return (props.fields || []).map(function (item) {
13075
+ let fieldPrefix = props.fieldPrefix;
13076
+ let fields = props.fields || [];
13077
+ if (fieldPrefix) {
13078
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13079
+ }
13080
+ return (fields || []).map(function (item) {
12991
13081
  let formItem = {
12992
13082
  "type": "steedos-field",
12993
13083
  "name": item.name,
@@ -13059,7 +13149,12 @@ async function getInputTableColumns(props) {
13059
13149
  let inlineEditMode = props.inlineEditMode;
13060
13150
  let showAsInlineEditMode = inlineEditMode && props.editable;
13061
13151
  // 实测过,直接不生成对应的隐藏column并不会对input-table值造成丢失问题,隐藏的列字段值能正常维护
13062
- let fields = props.fields;
13152
+
13153
+ let fieldPrefix = props.fieldPrefix;
13154
+ let fields = props.fields || [];
13155
+ if (fieldPrefix) {
13156
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13157
+ }
13063
13158
  if (columns && columns.length) {
13064
13159
  return columns.map(function (column) {
13065
13160
  let field, extendColumnProps = {};
@@ -13120,35 +13215,41 @@ function getFormPagination(props, mode) {
13120
13215
  let __formId = "${formId}";
13121
13216
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13122
13217
  let pageChangeDirection = context.props.pageChangeDirection;
13218
+ let mode = "${mode}";
13123
13219
  // event.data中的index和__page分别表示当前要把表单数据提交到的行索引和用于标定下一页页码的当前页页码
13124
13220
  // 一般来说__page = index + 1,但是可以让event.data中传入__page和index值不是这种联系。
13125
13221
  // 比如__page设置为3,index设置为0表示把当前表单数据提交到第一页,但是跳转到第4页,弹出的表单中底下的新增和复制按钮依赖了此功能
13126
13222
  // let currentPage = currentIndex + 1;
13127
13223
  let currentPage = event.data.__page;
13128
13224
  let currentIndex = event.data.index;
13129
- // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13130
- let currentFormValues = scope.getComponentById(__formId).getValues();
13131
- var parent = event.data.parent;
13132
- var __parentIndex = event.data.__parentIndex;
13133
- if(parent){
13134
- fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13135
- // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13136
- fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13137
- children: fieldValue[__parentIndex].children,
13138
- __fix_rerender_after_children_modified_tag: new Date().getTime()
13225
+ if(mode !== "readonly"){
13226
+ // 新建编辑时,翻页才需要把当前页表单保存,只读时直接翻页即可
13227
+ // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13228
+ let currentFormValues = scope.getComponentById(__formId).getValues();
13229
+ // 这里不clone的话,其值会带上__super属性
13230
+ currentFormValues = _.clone(currentFormValues);
13231
+ var parent = event.data.parent;
13232
+ var __parentIndex = event.data.__parentIndex;
13233
+ if(parent){
13234
+ fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13235
+ // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13236
+ fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13237
+ children: fieldValue[__parentIndex].children,
13238
+ __fix_rerender_after_children_modified_tag: new Date().getTime()
13239
+ });
13240
+ }
13241
+ else{
13242
+ fieldValue[currentIndex] = currentFormValues;
13243
+ }
13244
+ // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13245
+ doAction({
13246
+ "componentId": "${props.id}",
13247
+ "actionType": "setValue",
13248
+ "args": {
13249
+ "value": fieldValue
13250
+ }
13139
13251
  });
13140
13252
  }
13141
- else{
13142
- fieldValue[currentIndex] = currentFormValues;
13143
- }
13144
- // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13145
- doAction({
13146
- "componentId": "${props.id}",
13147
- "actionType": "setValue",
13148
- "args": {
13149
- "value": fieldValue
13150
- }
13151
- });
13152
13253
 
13153
13254
  // 以下是翻页逻辑,翻到下一页并把下一页内容显示到表单上
13154
13255
  let targetPage;
@@ -13208,7 +13309,7 @@ function getFormPagination(props, mode) {
13208
13309
  {
13209
13310
  "type": "tpl",
13210
13311
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13211
- "tpl": "${__page}/${__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length}"
13312
+ "tpl": "${__page}/${__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length}"
13212
13313
  },
13213
13314
  {
13214
13315
  "type": "button",
@@ -13218,7 +13319,7 @@ function getFormPagination(props, mode) {
13218
13319
  "pageChangeDirection": "next",
13219
13320
  // "disabledOn": showPagination ? "${__page >= __tableItems.length}" : "true",
13220
13321
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13221
- "disabledOn": showPagination ? "${__page >= (__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length)}" : "true",
13322
+ "disabledOn": showPagination ? "${__page >= (__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length)}" : "true",
13222
13323
  "size": "sm",
13223
13324
  "id": buttonNextId,
13224
13325
  "onEvent": {
@@ -13247,6 +13348,7 @@ function getFormPaginationWrapper(props, form, mode) {
13247
13348
  // console.log("==getFormPaginationWrapper===", props, mode);
13248
13349
  let serviceId = getComponentId("form_pagination", props.id);
13249
13350
  let tableServiceId = getComponentId("table_service", props.id);
13351
+ let primaryKey = getTablePrimaryKey(props);
13250
13352
  let innerForm = Object.assign({}, form, {
13251
13353
  "data": {
13252
13354
  // 这里加__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
@@ -13274,7 +13376,6 @@ function getFormPaginationWrapper(props, form, mode) {
13274
13376
  }
13275
13377
  ];
13276
13378
  let onServiceInitedScript = `
13277
-
13278
13379
  // 以下脚本解决了有时弹出编辑表单时,表单中的值比最后一次编辑保存的值会延迟一拍。
13279
13380
  // 比如:inlineEditMode模式时,用户在表格单元格中直接修改数据,然后弹出的表单form中并没有包含单元格中修改的内容
13280
13381
  // 另外有的地方在非inlineEditMode模式时也会有这种延迟一拍问题,比如对象字段中下拉框类型字段的”选择项“属性
@@ -13288,13 +13389,13 @@ function getFormPaginationWrapper(props, form, mode) {
13288
13389
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13289
13390
  // 这里如果不.clone的话,在弹出窗口中显示的子表组件,添加行后点窗口的取消按钮关闭窗口后无法把之前的操作还原,即把之前添加的行自动移除
13290
13391
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"] || []);
13291
- let fieldPrefix = "${props.fieldPrefix}";
13392
+ let fieldPrefix = "${props.fieldPrefix || ''}";
13292
13393
  if(fieldPrefix){
13293
13394
  let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
13294
13395
  lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
13295
13396
  }
13296
13397
  //不可以直接像event.data.__tableItems = lastestFieldValue; 这样整个赋值,否则作用域会断
13297
- let mode = "${mode}";
13398
+ let mode = "${mode || ''}";
13298
13399
  if(mode === "new"){
13299
13400
  // 点击子表组件底部新增按钮时新增一条空白行并自动翻页到新增行
13300
13401
  // 注意点击弹出的子表行详细表单中的新增按钮不会进此service init事件函数中
@@ -13320,10 +13421,20 @@ function getFormPaginationWrapper(props, form, mode) {
13320
13421
  var fieldValue = event.data.__tableItems;
13321
13422
  if(parent){
13322
13423
  // 如果是子行,即在节点嵌套情况下,当前节点如果是children属性下的子节点时,则算出其所属父行的索引值
13323
- var primaryKey = "${props.primaryKey}";
13424
+ var primaryKey = "${primaryKey}";
13324
13425
  event.data.__parentIndex = _.findIndex(fieldValue, function(item){
13325
13426
  return item[primaryKey] == parent[primaryKey];
13326
13427
  });
13428
+ if(event.data.__parentIndex < 0){
13429
+ let tableId = "${props.id}";
13430
+ let table = scope.getComponentById(tableId)
13431
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13432
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13433
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13434
+ event.data.__parentIndex = _.findIndex(table.props.value, function(item){
13435
+ return item[primaryKey] == parent[primaryKey];
13436
+ });
13437
+ }
13327
13438
  }
13328
13439
  `;
13329
13440
  let schema = {
@@ -13372,6 +13483,7 @@ function getFormPaginationWrapper(props, form, mode) {
13372
13483
  async function getForm(props, mode = "edit", formId) {
13373
13484
  let formFields = getFormFields(props, mode);
13374
13485
  let body = await getFormBody(null, formFields);
13486
+ let primaryKey = getTablePrimaryKey(props);
13375
13487
  if (!formId) {
13376
13488
  formId = getComponentId("form", props.id);
13377
13489
  }
@@ -13390,6 +13502,18 @@ async function getForm(props, mode = "edit", formId) {
13390
13502
  // 新增行弹出编辑行表单,在弹出之前已经不用先增加一行,因为在翻页service初始化的时候会判断mode为new时自动新增一行
13391
13503
  let onEditItemSubmitScript = `
13392
13504
  // let fieldValue = _.cloneDeep(event.data["${props.name}"]);
13505
+ let removeEmptyItems = function(items){
13506
+ let i = _.findIndex(items, function(item){
13507
+ return item === undefined
13508
+ });
13509
+ if(i > -1){
13510
+ items.splice(i, 1);
13511
+ removeEmptyItems(items);
13512
+ }
13513
+ }
13514
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13515
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13516
+ removeEmptyItems(event.data.__tableItems);
13393
13517
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13394
13518
  //这里加__super.__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
13395
13519
  // 比如“对象字段”对象options字段是一个子表字段,但是主表(即“对象字段”对象)中正好有一个名为index的字段
@@ -13398,6 +13522,8 @@ async function getForm(props, mode = "edit", formId) {
13398
13522
  var currentFormValues = JSON.parse(JSON.stringify(event.data));
13399
13523
  var parent = event.data.__super.__super.parent;
13400
13524
  var __parentIndex = event.data.__super.__super.__parentIndex;
13525
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13526
+ var primaryKey = "${primaryKey}";
13401
13527
  if(parent){
13402
13528
  fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13403
13529
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13407,6 +13533,8 @@ async function getForm(props, mode = "edit", formId) {
13407
13533
  });
13408
13534
  }
13409
13535
  else{
13536
+ // 这里currentFormValues中如果没有primaryKey字段值不用处理,因为组件的pipeIn/pipeOut中会为每行自动生成
13537
+ // 也不用担心复制行时_id会重复,因为点击复制按钮时已经处理过了
13410
13538
  fieldValue[currentIndex] = currentFormValues;
13411
13539
  }
13412
13540
  doAction({
@@ -13504,6 +13632,7 @@ async function getForm(props, mode = "edit", formId) {
13504
13632
  */
13505
13633
  async function getButtonActions(props, mode) {
13506
13634
  let actions = [];
13635
+ let primaryKey = getTablePrimaryKey(props);
13507
13636
  let formId = getComponentId("form", props.id);
13508
13637
  let dialogId = getComponentId("dialog", props.id);
13509
13638
  let buttonNextId = getComponentId("button_next", props.id);
@@ -13546,13 +13675,35 @@ async function getButtonActions(props, mode) {
13546
13675
  // };
13547
13676
  let onSaveAndNewItemScript = `
13548
13677
  let scope = event.context.scoped;
13678
+ let removeEmptyItems = function(items){
13679
+ let i = _.findIndex(items, function(item){
13680
+ return item === undefined
13681
+ });
13682
+ if(i > -1){
13683
+ items.splice(i, 1);
13684
+ removeEmptyItems(items);
13685
+ }
13686
+ }
13687
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13688
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13689
+ removeEmptyItems(event.data.__tableItems);
13549
13690
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13550
13691
  // 新建一条空白行并保存到子表组件
13551
13692
  var parent = event.data.__super.parent;
13552
- var primaryKey = "${props.primaryKey}";
13693
+ var primaryKey = "${primaryKey}";
13553
13694
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13554
13695
  return item[primaryKey] == parent[primaryKey];
13555
13696
  });
13697
+ if(parent && __parentIndex < 0){
13698
+ let tableId = "${props.id}";
13699
+ let table = scope.getComponentById(tableId)
13700
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13701
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13702
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13703
+ __parentIndex = _.findIndex(table.props.value, function(item){
13704
+ return item[primaryKey] == parent[primaryKey];
13705
+ });
13706
+ }
13556
13707
  if(parent){
13557
13708
  fieldValue[__parentIndex].children.push({});
13558
13709
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13586,14 +13737,42 @@ async function getButtonActions(props, mode) {
13586
13737
  let __formId = "${formId}";
13587
13738
  // let newItem = JSON.parse(JSON.stringify(event.data));
13588
13739
  let newItem = scope.getComponentById(__formId).getValues();//这里不可以用event.data,因为其拿到的是弹出表单时的初始值,不是用户实时填写的数据
13740
+ newItem = _.clone(newItem);
13741
+ let removeEmptyItems = function(items){
13742
+ let i = _.findIndex(items, function(item){
13743
+ return item === undefined
13744
+ });
13745
+ if(i > -1){
13746
+ items.splice(i, 1);
13747
+ removeEmptyItems(items);
13748
+ }
13749
+ }
13750
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13751
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13752
+ removeEmptyItems(event.data.__tableItems);
13589
13753
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13590
13754
  // 复制当前页数据到新建行并保存到子表组件
13591
13755
  // fieldValue.push(newItem);
13592
13756
  var parent = event.data.__super.parent;
13593
- var primaryKey = "${props.primaryKey}";
13757
+ var primaryKey = "${primaryKey}";
13594
13758
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13595
13759
  return item[primaryKey] == parent[primaryKey];
13596
13760
  });
13761
+ if(parent && __parentIndex < 0){
13762
+ let tableId = "${props.id}";
13763
+ let table = scope.getComponentById(tableId)
13764
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13765
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13766
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13767
+ __parentIndex = _.findIndex(table.props.value, function(item){
13768
+ return item[primaryKey] == parent[primaryKey];
13769
+ });
13770
+ }
13771
+ if(newItem[primaryKey]){
13772
+ // 如果newItem已经有主键字段值,则重新生成新的主键值,否则会重复。
13773
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13774
+ newItem[primaryKey] = uuidv4();
13775
+ }
13597
13776
  if(parent){
13598
13777
  fieldValue[__parentIndex].children.push(newItem);
13599
13778
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13801,7 +13980,10 @@ async function getButtonActions(props, mode) {
13801
13980
  // 为了解决"弹出的dialog窗口中子表组件会影响页面布局界面中父作用域字段值",比如设计字段布局微页面中的设置分组功能,弹出的就是子表dialog
13802
13981
  // 所以这里使用json|toJson转一次,断掉event.data.__tableItems与上层任用域中props.name的联系
13803
13982
  // "__tableItems": `\${${props.name}|json|toJson}`
13804
- "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13983
+ // "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13984
+ // 在节点嵌套情况下,当前节点正好是带children属性的节点的话,这里弹出的dialog映射到的会是children数组,这是amis目前的规则,
13985
+ // 所以这里加判断有children时,用__super.__super让映射到正确的作用域层,如果不加,则__tableItems取到的会是children数组,而不是整个子表组件的值
13986
+ "__tableItems": `\${((children ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13805
13987
  },
13806
13988
  }
13807
13989
  }
@@ -13817,13 +13999,24 @@ async function getButtonActions(props, mode) {
13817
13999
  let wrapperServiceData = wrapperService.getData();
13818
14000
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13819
14001
  // 这里_.clone是因为字段设计布局设置分组这种弹出窗口中的子表组件,直接删除后,点取消无法还原
14002
+ // 也因为这里clone没有直接删除,所以弹出编辑表单提交事件中event.data.__tableItems中取到的值会有被删除的行数据为undefined
13820
14003
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"]);
13821
14004
  var currentIndex = event.data.index;
13822
14005
  var parent = event.data.__super.parent;
13823
- var primaryKey = "${props.primaryKey}";
14006
+ var primaryKey = "${primaryKey}";
13824
14007
  var __parentIndex = parent && _.findIndex(lastestFieldValue, function(item){
13825
14008
  return item[primaryKey] == parent[primaryKey];
13826
14009
  });
14010
+ if(parent && __parentIndex < 0){
14011
+ let tableId = "${props.id}";
14012
+ let table = scope.getComponentById(tableId)
14013
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
14014
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
14015
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
14016
+ __parentIndex = _.findIndex(table.props.value, function(item){
14017
+ return item[primaryKey] == parent[primaryKey];
14018
+ });
14019
+ }
13827
14020
  if(parent){
13828
14021
  lastestFieldValue[__parentIndex].children.splice(currentIndex, 1);
13829
14022
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13835,6 +14028,11 @@ async function getButtonActions(props, mode) {
13835
14028
  else{
13836
14029
  lastestFieldValue.splice(currentIndex, 1);
13837
14030
  }
14031
+ let fieldPrefix = "${props.fieldPrefix || ''}";
14032
+ if(fieldPrefix){
14033
+ let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
14034
+ lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
14035
+ }
13838
14036
  doAction({
13839
14037
  "componentId": "${props.id}",
13840
14038
  "actionType": "setValue",
@@ -13920,16 +14118,15 @@ const getAmisInputTableSchema = async (props) => {
13920
14118
  if (!props.id) {
13921
14119
  props.id = "steedos_input_table_" + props.name + "_" + Math.random().toString(36).substr(2, 9);
13922
14120
  }
13923
- if (!props.primaryKey) {
13924
- props.primaryKey = "_id";
13925
- }
14121
+ let primaryKey = getTablePrimaryKey(props);
13926
14122
  let showOperation = props.showOperation;
13927
14123
  if(showOperation !== false){
13928
14124
  showOperation = true;
13929
14125
  }
13930
- // props.fieldPrefix = "project_milestone_";
13931
- if (props.fieldPrefix) {
13932
- props.fields = getTableFieldsWithoutFieldPrefix(props.fields, props.fieldPrefix);
14126
+ let fieldPrefix = props.fieldPrefix;
14127
+ let fields = props.fields || [];
14128
+ if (fieldPrefix) {
14129
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13933
14130
  }
13934
14131
  let serviceId = getComponentId("table_service", props.id);
13935
14132
  let buttonsForColumnOperations = [];
@@ -13942,7 +14139,7 @@ const getAmisInputTableSchema = async (props) => {
13942
14139
  // 始终显示弹出子表表单按钮,如果需要判断只在有列被隐藏时才需要显示弹出表单按钮放开下面的if逻辑就好
13943
14140
  showEditButton = true;
13944
14141
  // // inline edit模式下只在有列被隐藏时才需要显示编辑按钮
13945
- // if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length) {
14142
+ // if (props.columns && props.columns.length > 0 && props.columns.length < fields.length) {
13946
14143
  // showEditButton = true;
13947
14144
  // }
13948
14145
  // else {
@@ -13957,7 +14154,7 @@ const getAmisInputTableSchema = async (props) => {
13957
14154
  }
13958
14155
  else {
13959
14156
  // 只读时显示查看按钮
13960
- // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length)
14157
+ // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < fields.length)
13961
14158
  let buttonViewSchema = await getButtonView(props);
13962
14159
  buttonsForColumnOperations.push(buttonViewSchema);
13963
14160
  }
@@ -13966,10 +14163,10 @@ const getAmisInputTableSchema = async (props) => {
13966
14163
  buttonsForColumnOperations.push(buttonDeleteSchema);
13967
14164
  }
13968
14165
  }
13969
- let amis = props["input-table"] || props.amis;//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
14166
+ let amis = props["input-table"] || props.amis || {};//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
13970
14167
  let inputTableSchema = {
13971
14168
  "type": "input-table",
13972
- "label": props.label,
14169
+ "mode": "normal",
13973
14170
  "name": props.name,
13974
14171
  //不可以addable/editable/removable设置为true,因为会在原生的操作列显示操作按钮图标,此开关实测只控制这个按钮显示不会影响功能
13975
14172
  // "addable": props.addable,
@@ -13985,13 +14182,42 @@ const getAmisInputTableSchema = async (props) => {
13985
14182
  "showTableAddBtn": false,
13986
14183
  "showFooterAddBtn": false,
13987
14184
  "className": props.tableClassName,
14185
+ "pipeIn": (value, data) => {
14186
+ if(fieldPrefix){
14187
+ value = getTableValueWithoutFieldPrefix(value, fieldPrefix);
14188
+ }
14189
+ if(primaryKey){
14190
+ // 这里临时给每行数据补上primaryKey字段值,如果库里不需要保存这里补上的字段值,pipeOut中会识别autoGeneratePrimaryKeyValue属性选择最终移除这里补上的字段值
14191
+ // 这里始终自动生成primaryKey字段值,而不是只在pipeOut输出整个子表字段值时才生成,是因为要支持当数据库里保存的子表字段行数据没有primaryKey字段值时的行嵌套模式(即节点的children属性)功能
14192
+ // 这里要注意,流程详细设置界面的字段设置功能中的子表组件中,数据库里保存的子表字段行数据是有primaryKey字段值的,它不依赖这里自动生成行primaryKey值功能
14193
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14194
+ }
14195
+ if(amis.pipeIn){
14196
+ if(typeof amis.pipeIn === 'function'){
14197
+ return amis.pipeIn(value, data);
14198
+ }
14199
+ }
14200
+ return value;
14201
+ },
13988
14202
  "pipeOut": (value, data) => {
13989
14203
  value = (value || []).map(function(item){
13990
14204
  delete item.__fix_rerender_after_children_modified_tag;
13991
14205
  return item;
13992
14206
  });
13993
- if(props.fieldPrefix){
13994
- value = getTableValuePrependFieldPrefix(value, props.fieldPrefix);
14207
+ if(fieldPrefix){
14208
+ value = getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey);
14209
+ }
14210
+ if(props.autoGeneratePrimaryKeyValue === true){
14211
+ // 如果需要把自动生成的primaryKey值输出保存的库中,则补全所有行中的primaryKey值
14212
+ // 这里如果不全部补全的话,初始从库里返回的字段值中拿到的行没primaryKey值的话就不会自动补上
14213
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14214
+ }
14215
+ else {
14216
+ // 默认情况下,也就是没有配置autoGeneratePrimaryKey时,最终输出的字段值要移除行中的primaryKey值
14217
+ // 需要注意如果没有配置autoGeneratePrimaryKey时,因为每次弹出行编辑窗口保存后都会先后进入pipeOut和pipeIn,
14218
+ // 这里删除掉了primaryKey值,所以primaryKey值每次弹出编辑窗口保存后都会给每行重新生成新的primaryKey值
14219
+ // 只有autoGeneratePrimaryKey配置为true时,每行的primaryKey字段值才会始终保持不变
14220
+ value = getTableValueWithoutPrimaryKeyValue(value, primaryKey);
13995
14221
  }
13996
14222
  if(amis.pipeOut){
13997
14223
  if(typeof amis.pipeOut === 'function'){
@@ -14001,20 +14227,6 @@ const getAmisInputTableSchema = async (props) => {
14001
14227
  return value;
14002
14228
  }
14003
14229
  };
14004
- if(amis.pipeIn){
14005
- inputTableSchema.pipeIn = amis.pipeIn;
14006
- }
14007
- if(props.fieldPrefix){
14008
- inputTableSchema.pipeIn = (value, data) => {
14009
- value = getTableValueWithoutFieldPrefix(value, props.fieldPrefix);
14010
- if(amis.pipeIn){
14011
- if(typeof amis.pipeIn === 'function'){
14012
- return amis.pipeIn(value, data);
14013
- }
14014
- }
14015
- return value;
14016
- };
14017
- }
14018
14230
  if (buttonsForColumnOperations.length) {
14019
14231
  inputTableSchema.columns.push({
14020
14232
  "name": "__op__",
@@ -14033,7 +14245,7 @@ const getAmisInputTableSchema = async (props) => {
14033
14245
  delete amis.pipeOut;//该属性在上面合并过了
14034
14246
  Object.assign(inputTableSchema, amis);
14035
14247
  }
14036
- const isAnyFieldHasDependOn = (props.fields || []).find(function (item) {
14248
+ const isAnyFieldHasDependOn = (fields || []).find(function (item) {
14037
14249
  return item.depend_on;
14038
14250
  });
14039
14251
  if (isAnyFieldHasDependOn) {
@@ -14068,7 +14280,16 @@ const getAmisInputTableSchema = async (props) => {
14068
14280
  }
14069
14281
  let schema = {
14070
14282
  "type": "service",
14071
- "body": schemaBody,
14283
+ "body": [
14284
+ {
14285
+ "type": "control",
14286
+ "body": schemaBody,
14287
+ "label": props.label,
14288
+ "labelClassName": props.label ? props.labelClassName : "none",
14289
+ "labelRemark": props.labelRemark,
14290
+ "labelAlign": props.labelAlign
14291
+ }
14292
+ ],
14072
14293
  "className": props.className,
14073
14294
  "id": serviceId
14074
14295
  };