@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.cjs.js CHANGED
@@ -381,6 +381,9 @@ const Router = {
381
381
  if(uiSchema.enable_split){
382
382
  defaultDisplay = "split";
383
383
  }
384
+ if(window.innerWidth <= 768){
385
+ return "grid";
386
+ }
384
387
  return value ? value : defaultDisplay;
385
388
  },
386
389
 
@@ -1308,6 +1311,7 @@ var frontend_notifications$1 = "Notifications";
1308
1311
  var frontend_notifications_allread$1 = "Mark all as read";
1309
1312
  var frontend_notifications_allread_message$1 = "All marked as read";
1310
1313
  var frontend_profile$1 = "Profile";
1314
+ var switch_space$1 = "Switch Space";
1311
1315
  var frontend_about$1 = "About";
1312
1316
  var frontend_log_out$1 = "Log out";
1313
1317
  var frontend_listview_warning_start$1 = "The current ";
@@ -1395,6 +1399,7 @@ var en_us = {
1395
1399
  frontend_notifications_allread: frontend_notifications_allread$1,
1396
1400
  frontend_notifications_allread_message: frontend_notifications_allread_message$1,
1397
1401
  frontend_profile: frontend_profile$1,
1402
+ switch_space: switch_space$1,
1398
1403
  frontend_about: frontend_about$1,
1399
1404
  frontend_log_out: frontend_log_out$1,
1400
1405
  frontend_listview_warning_start: frontend_listview_warning_start$1,
@@ -1484,6 +1489,7 @@ var frontend_notifications = "通知";
1484
1489
  var frontend_notifications_allread = "全部标记为已读";
1485
1490
  var frontend_notifications_allread_message = "已全部标记为已读";
1486
1491
  var frontend_profile = "个人资料";
1492
+ var switch_space = "切换工作区";
1487
1493
  var frontend_about = "关于";
1488
1494
  var frontend_log_out = "注销";
1489
1495
  var frontend_listview_warning_start = "当前";
@@ -1572,6 +1578,7 @@ var zh_cn = {
1572
1578
  frontend_notifications_allread: frontend_notifications_allread,
1573
1579
  frontend_notifications_allread_message: frontend_notifications_allread_message,
1574
1580
  frontend_profile: frontend_profile,
1581
+ switch_space: switch_space,
1575
1582
  frontend_about: frontend_about,
1576
1583
  frontend_log_out: frontend_log_out,
1577
1584
  frontend_listview_warning_start: frontend_listview_warning_start,
@@ -2060,7 +2067,7 @@ async function getQuickEditSchema(field, options){
2060
2067
  }
2061
2068
 
2062
2069
  function getFieldWidth(width){
2063
- const defaultWidth = "unset";//用于使table内的td标签下生成div,实现将快速编辑按钮固定在右侧的效果,并不是为了unset效果
2070
+ const defaultWidth = null;
2064
2071
  if(typeof width == 'string'){
2065
2072
  if(isNaN(width)){
2066
2073
  return width || defaultWidth;
@@ -2090,14 +2097,14 @@ async function getTableColumns(fields, options){
2090
2097
  //增加quickEdit属性,实现快速编辑
2091
2098
  const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
2092
2099
  let className = "";
2093
- if(field.wrap != true){
2094
- if(field.wrap != false && field.is_wide){
2095
- className += " break-words ";
2096
- }else {
2100
+ if(/Safari/.test(navigator.userAgent)){
2101
+ className += " whitespace-nowrap ";
2102
+ }else {
2103
+ if(field.wrap != true){
2097
2104
  className += " whitespace-nowrap ";
2105
+ }else {
2106
+ className += " break-words ";
2098
2107
  }
2099
- }else {
2100
- className += " break-words ";
2101
2108
  }
2102
2109
  let columnItem;
2103
2110
  if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
@@ -10655,17 +10662,13 @@ function getReferenceToSync(field) {
10655
10662
 
10656
10663
  function getLookupSapceUserTreeSchema(isMobile){
10657
10664
  let apiAdaptor = `
10658
- // console.log("===getLookupSapceUserTreeSchema===", JSON.stringify(payload));
10659
10665
  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
10666
  const treeRecords = [];
10668
- const getChildren = (records, childrenIds) => {
10667
+ const getChildren = (currentRecord, records, childrenIds) => {
10668
+ if (currentRecord.children && typeof currentRecord.children[0] === "object") {
10669
+ // 考虑api配置了cache缓存的话,不会请求接口但是会重新进这个接收适配器脚本且payload.data.options返回的会是上一次计算结果,这里直接返回计算过的children
10670
+ return currentRecord.children;
10671
+ }
10669
10672
  if (!childrenIds) {
10670
10673
  return;
10671
10674
  }
@@ -10674,7 +10677,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10674
10677
  });
10675
10678
  _.each(children, (item) => {
10676
10679
  if (item.children) {
10677
- item.children = getChildren(records, item.children)
10680
+ item.children = getChildren(item, records, item.children)
10678
10681
  }else{
10679
10682
  item.children = [];
10680
10683
  }
@@ -10700,7 +10703,7 @@ function getLookupSapceUserTreeSchema(isMobile){
10700
10703
 
10701
10704
  _.each(records, (record) => {
10702
10705
  if (record.noParent == 1) {
10703
- treeRecords.push(Object.assign({}, record, { children: getChildren(records, record.children) }));
10706
+ treeRecords.push(Object.assign({}, record, { children: getChildren(record, records, record.children) }));
10704
10707
  }
10705
10708
  });
10706
10709
  console.log(treeRecords)
@@ -12546,7 +12549,7 @@ async function convertSFieldToAmisField(field, readonly, ctx) {
12546
12549
  }else {
12547
12550
  convertData.className = 'm-0';
12548
12551
  }
12549
- if(readonly){
12552
+ if(readonly && ctx.mode !== 'edit'){
12550
12553
  convertData.className = `${convertData.className} border-b`;
12551
12554
  }
12552
12555
  if(readonly){
@@ -12828,6 +12831,13 @@ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectio
12828
12831
  }
12829
12832
  }
12830
12833
 
12834
+ fieldSetBody.forEach((field)=>{
12835
+ //判断label是否存在,不存在时将label的空占位元素隐藏
12836
+ if(!field.label){
12837
+ field.labelClassName = "none";
12838
+ }
12839
+ });
12840
+
12831
12841
  // fieldSet 已支持显隐控制
12832
12842
  const sectionFieldsVisibleOn = ___namespace.map(___namespace.compact(___namespace.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
12833
12843
  let visible = visibleOn;
@@ -12950,13 +12960,83 @@ async function getFormBody(permissionFields, formFields, ctx){
12950
12960
  return await getSections(permissionFields, formFields, ctx);
12951
12961
  }
12952
12962
 
12963
+ /*
12964
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
12965
+ * @Date: 2024-01-18 15:12:41
12966
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12967
+ * @LastEditTime: 2024-01-18 15:12:49
12968
+ */
12969
+ /**
12970
+ * 生成符合标准uuid格式的36位满足唯一性的随机串
12971
+ * @returns uuid
12972
+ */
12973
+ function uuidv4() {
12974
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
12975
+ (c ^ window.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
12976
+ );
12977
+ }
12978
+
12953
12979
  /*
12954
12980
  * @Author: 殷亮辉 yinlianghui@hotoa.com
12955
12981
  * @Date: 2023-11-15 09:50:22
12956
12982
  * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
12957
- * @LastEditTime: 2024-01-18 10:29:57
12983
+ * @LastEditTime: 2024-01-22 15:59:32
12958
12984
  */
12959
12985
 
12986
+ function getTablePrimaryKey(props){
12987
+ return props.primaryKey || "_id";
12988
+ }
12989
+
12990
+ /**
12991
+ * 子表组件字段值中每行数据的补上唯一标识字段值,其值为随机uuid
12992
+ * @param {*} value 子表组件字段值,数组
12993
+ * @param {*} primaryKey 主键字段名,一般为_id
12994
+ * @returns 转换后的子表组件字段值
12995
+ */
12996
+ function getTableValueWithPrimaryKeyValue(value, primaryKey){
12997
+ if(!primaryKey){
12998
+ return value;
12999
+ }
13000
+ return (value || []).map((itemValue)=>{
13001
+ //这里不clone的话,会造成在pipeIn函数执行该函数后像pipeOut一样最终输出到表单项中,即库里把primaryKey字段值保存了
13002
+ const newItemValue = _$1.clone(itemValue);
13003
+ if(newItemValue[primaryKey]){
13004
+ if(newItemValue.children){
13005
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
13006
+ }
13007
+ return newItemValue;
13008
+ }
13009
+ else {
13010
+ newItemValue[primaryKey] = uuidv4();
13011
+ if(newItemValue.children){
13012
+ newItemValue.children = getTableValueWithPrimaryKeyValue(newItemValue.children, primaryKey);
13013
+ }
13014
+ return newItemValue;
13015
+ }
13016
+ });
13017
+ }
13018
+
13019
+ /**
13020
+ * 子表组件字段值中每行数据的移除唯一标识字段值,因为该字段值一般只作临时标记,不存库
13021
+ * @param {*} value 子表组件字段值,数组
13022
+ * @param {*} primaryKey 主键字段名,一般为_id
13023
+ * @returns 转换后的子表组件字段值
13024
+ */
13025
+ function getTableValueWithoutPrimaryKeyValue(value, primaryKey){
13026
+ if(!primaryKey){
13027
+ return value;
13028
+ }
13029
+ return (value || []).map((itemValue)=>{
13030
+ //这里clone只是为了保险,不是必须的,每次修改子表数据是否都会生成新的primaryKey字段值是由pipeOut中识别autoGeneratePrimaryKeyValue决定的,跟这里没关系
13031
+ const newItemValue = _$1.clone(itemValue);
13032
+ if(newItemValue.children){
13033
+ newItemValue.children = getTableValueWithoutPrimaryKeyValue(newItemValue.children, primaryKey);
13034
+ }
13035
+ delete newItemValue[primaryKey];
13036
+ return newItemValue;
13037
+ });
13038
+ }
13039
+
12960
13040
  /**
12961
13041
  * 子表组件字段值中每行数据的键值key移除指定前缀
12962
13042
  * @param {*} value 子表组件字段值,数组
@@ -12968,7 +13048,9 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12968
13048
  (value || []).forEach((itemValue)=>{
12969
13049
  var newItemValue = {};
12970
13050
  for(let n in itemValue){
12971
- newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13051
+ if(itemValue.hasOwnProperty(n)){
13052
+ newItemValue[n.replace(new RegExp(`^${fieldPrefix}`), "")] = itemValue[n];
13053
+ }
12972
13054
  }
12973
13055
  convertedValue.push(newItemValue);
12974
13056
  });
@@ -12981,15 +13063,18 @@ function getTableValueWithoutFieldPrefix(value, fieldPrefix){
12981
13063
  * @param {*} fieldPrefix 字段前缀
12982
13064
  * @returns 转换后的子表组件字段值
12983
13065
  */
12984
- function getTableValuePrependFieldPrefix(value, fieldPrefix){
13066
+ function getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey){
12985
13067
  let convertedValue = [];
12986
13068
  (value || []).forEach((itemValue)=>{
12987
13069
  var newItemValue = {};
12988
13070
  for(let n in itemValue){
12989
- if(typeof itemValue[n] !== undefined){
13071
+ if(itemValue.hasOwnProperty(n) && typeof itemValue[n] !== undefined && n !== primaryKey){
12990
13072
  newItemValue[`${fieldPrefix}${n}`] = itemValue[n];
12991
13073
  }
12992
13074
  }
13075
+ if(primaryKey && itemValue[primaryKey]){
13076
+ newItemValue[primaryKey] = itemValue[primaryKey];
13077
+ }
12993
13078
  convertedValue.push(newItemValue);
12994
13079
  });
12995
13080
  return convertedValue;
@@ -13014,7 +13099,12 @@ function getTableFieldsWithoutFieldPrefix(fields, fieldPrefix){
13014
13099
  * @param {*} mode edit/new/readonly
13015
13100
  */
13016
13101
  function getFormFields(props, mode = "edit") {
13017
- return (props.fields || []).map(function (item) {
13102
+ let fieldPrefix = props.fieldPrefix;
13103
+ let fields = props.fields || [];
13104
+ if (fieldPrefix) {
13105
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13106
+ }
13107
+ return (fields || []).map(function (item) {
13018
13108
  let formItem = {
13019
13109
  "type": "steedos-field",
13020
13110
  "name": item.name,
@@ -13086,7 +13176,12 @@ async function getInputTableColumns(props) {
13086
13176
  let inlineEditMode = props.inlineEditMode;
13087
13177
  let showAsInlineEditMode = inlineEditMode && props.editable;
13088
13178
  // 实测过,直接不生成对应的隐藏column并不会对input-table值造成丢失问题,隐藏的列字段值能正常维护
13089
- let fields = props.fields;
13179
+
13180
+ let fieldPrefix = props.fieldPrefix;
13181
+ let fields = props.fields || [];
13182
+ if (fieldPrefix) {
13183
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13184
+ }
13090
13185
  if (columns && columns.length) {
13091
13186
  return columns.map(function (column) {
13092
13187
  let field, extendColumnProps = {};
@@ -13147,35 +13242,41 @@ function getFormPagination(props, mode) {
13147
13242
  let __formId = "${formId}";
13148
13243
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13149
13244
  let pageChangeDirection = context.props.pageChangeDirection;
13245
+ let mode = "${mode}";
13150
13246
  // event.data中的index和__page分别表示当前要把表单数据提交到的行索引和用于标定下一页页码的当前页页码
13151
13247
  // 一般来说__page = index + 1,但是可以让event.data中传入__page和index值不是这种联系。
13152
13248
  // 比如__page设置为3,index设置为0表示把当前表单数据提交到第一页,但是跳转到第4页,弹出的表单中底下的新增和复制按钮依赖了此功能
13153
13249
  // let currentPage = currentIndex + 1;
13154
13250
  let currentPage = event.data.__page;
13155
13251
  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()
13252
+ if(mode !== "readonly"){
13253
+ // 新建编辑时,翻页才需要把当前页表单保存,只读时直接翻页即可
13254
+ // 翻页到下一页之前需要先把当前页改动的内容保存到中间变量__tableItems中
13255
+ let currentFormValues = scope.getComponentById(__formId).getValues();
13256
+ // 这里不clone的话,其值会带上__super属性
13257
+ currentFormValues = _.clone(currentFormValues);
13258
+ var parent = event.data.parent;
13259
+ var __parentIndex = event.data.__parentIndex;
13260
+ if(parent){
13261
+ fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13262
+ // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
13263
+ fieldValue[__parentIndex] = Object.assign({}, fieldValue[__parentIndex], {
13264
+ children: fieldValue[__parentIndex].children,
13265
+ __fix_rerender_after_children_modified_tag: new Date().getTime()
13266
+ });
13267
+ }
13268
+ else{
13269
+ fieldValue[currentIndex] = currentFormValues;
13270
+ }
13271
+ // 翻页到下一页前需要同时把改动的内容保存到最终正式的表单字段中,所以额外给正式表单字段执行一次setValue
13272
+ doAction({
13273
+ "componentId": "${props.id}",
13274
+ "actionType": "setValue",
13275
+ "args": {
13276
+ "value": fieldValue
13277
+ }
13166
13278
  });
13167
13279
  }
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
13280
 
13180
13281
  // 以下是翻页逻辑,翻到下一页并把下一页内容显示到表单上
13181
13282
  let targetPage;
@@ -13235,7 +13336,7 @@ function getFormPagination(props, mode) {
13235
13336
  {
13236
13337
  "type": "tpl",
13237
13338
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13238
- "tpl": "${__page}/${__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length}"
13339
+ "tpl": "${__page}/${__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length}"
13239
13340
  },
13240
13341
  {
13241
13342
  "type": "button",
@@ -13245,7 +13346,7 @@ function getFormPagination(props, mode) {
13245
13346
  "pageChangeDirection": "next",
13246
13347
  // "disabledOn": showPagination ? "${__page >= __tableItems.length}" : "true",
13247
13348
  // 这里用__super.parent,加__super是为了防止当前记录有字段名为parent的重名变量
13248
- "disabledOn": showPagination ? "${__page >= (__super.parent ? __tableItems[__parentIndex]['children'].length : __tableItems.length)}" : "true",
13349
+ "disabledOn": showPagination ? "${__page >= (__super.parent ? COMPACT(__tableItems[__parentIndex]['children']).length : COMPACT(__tableItems).length)}" : "true",
13249
13350
  "size": "sm",
13250
13351
  "id": buttonNextId,
13251
13352
  "onEvent": {
@@ -13274,6 +13375,7 @@ function getFormPaginationWrapper(props, form, mode) {
13274
13375
  // console.log("==getFormPaginationWrapper===", props, mode);
13275
13376
  let serviceId = getComponentId("form_pagination", props.id);
13276
13377
  let tableServiceId = getComponentId("table_service", props.id);
13378
+ let primaryKey = getTablePrimaryKey(props);
13277
13379
  let innerForm = Object.assign({}, form, {
13278
13380
  "data": {
13279
13381
  // 这里加__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
@@ -13301,7 +13403,6 @@ function getFormPaginationWrapper(props, form, mode) {
13301
13403
  }
13302
13404
  ];
13303
13405
  let onServiceInitedScript = `
13304
-
13305
13406
  // 以下脚本解决了有时弹出编辑表单时,表单中的值比最后一次编辑保存的值会延迟一拍。
13306
13407
  // 比如:inlineEditMode模式时,用户在表格单元格中直接修改数据,然后弹出的表单form中并没有包含单元格中修改的内容
13307
13408
  // 另外有的地方在非inlineEditMode模式时也会有这种延迟一拍问题,比如对象字段中下拉框类型字段的”选择项“属性
@@ -13315,13 +13416,13 @@ function getFormPaginationWrapper(props, form, mode) {
13315
13416
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13316
13417
  // 这里如果不.clone的话,在弹出窗口中显示的子表组件,添加行后点窗口的取消按钮关闭窗口后无法把之前的操作还原,即把之前添加的行自动移除
13317
13418
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"] || []);
13318
- let fieldPrefix = "${props.fieldPrefix}";
13419
+ let fieldPrefix = "${props.fieldPrefix || ''}";
13319
13420
  if(fieldPrefix){
13320
13421
  let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
13321
13422
  lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
13322
13423
  }
13323
13424
  //不可以直接像event.data.__tableItems = lastestFieldValue; 这样整个赋值,否则作用域会断
13324
- let mode = "${mode}";
13425
+ let mode = "${mode || ''}";
13325
13426
  if(mode === "new"){
13326
13427
  // 点击子表组件底部新增按钮时新增一条空白行并自动翻页到新增行
13327
13428
  // 注意点击弹出的子表行详细表单中的新增按钮不会进此service init事件函数中
@@ -13347,10 +13448,20 @@ function getFormPaginationWrapper(props, form, mode) {
13347
13448
  var fieldValue = event.data.__tableItems;
13348
13449
  if(parent){
13349
13450
  // 如果是子行,即在节点嵌套情况下,当前节点如果是children属性下的子节点时,则算出其所属父行的索引值
13350
- var primaryKey = "${props.primaryKey}";
13451
+ var primaryKey = "${primaryKey}";
13351
13452
  event.data.__parentIndex = _.findIndex(fieldValue, function(item){
13352
13453
  return item[primaryKey] == parent[primaryKey];
13353
13454
  });
13455
+ if(event.data.__parentIndex < 0){
13456
+ let tableId = "${props.id}";
13457
+ let table = scope.getComponentById(tableId)
13458
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13459
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13460
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13461
+ event.data.__parentIndex = _.findIndex(table.props.value, function(item){
13462
+ return item[primaryKey] == parent[primaryKey];
13463
+ });
13464
+ }
13354
13465
  }
13355
13466
  `;
13356
13467
  let schema = {
@@ -13399,6 +13510,7 @@ function getFormPaginationWrapper(props, form, mode) {
13399
13510
  async function getForm(props, mode = "edit", formId) {
13400
13511
  let formFields = getFormFields(props, mode);
13401
13512
  let body = await getFormBody(null, formFields);
13513
+ let primaryKey = getTablePrimaryKey(props);
13402
13514
  if (!formId) {
13403
13515
  formId = getComponentId("form", props.id);
13404
13516
  }
@@ -13417,6 +13529,18 @@ async function getForm(props, mode = "edit", formId) {
13417
13529
  // 新增行弹出编辑行表单,在弹出之前已经不用先增加一行,因为在翻页service初始化的时候会判断mode为new时自动新增一行
13418
13530
  let onEditItemSubmitScript = `
13419
13531
  // let fieldValue = _.cloneDeep(event.data["${props.name}"]);
13532
+ let removeEmptyItems = function(items){
13533
+ let i = _.findIndex(items, function(item){
13534
+ return item === undefined
13535
+ });
13536
+ if(i > -1){
13537
+ items.splice(i, 1);
13538
+ removeEmptyItems(items);
13539
+ }
13540
+ }
13541
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13542
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13543
+ removeEmptyItems(event.data.__tableItems);
13420
13544
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13421
13545
  //这里加__super.__super前缀是因为__parentForm变量(即主表单)中可能会正好有名为index的字段
13422
13546
  // 比如“对象字段”对象options字段是一个子表字段,但是主表(即“对象字段”对象)中正好有一个名为index的字段
@@ -13425,6 +13549,8 @@ async function getForm(props, mode = "edit", formId) {
13425
13549
  var currentFormValues = JSON.parse(JSON.stringify(event.data));
13426
13550
  var parent = event.data.__super.__super.parent;
13427
13551
  var __parentIndex = event.data.__super.__super.__parentIndex;
13552
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13553
+ var primaryKey = "${primaryKey}";
13428
13554
  if(parent){
13429
13555
  fieldValue[__parentIndex].children[currentIndex] = currentFormValues;
13430
13556
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13434,6 +13560,8 @@ async function getForm(props, mode = "edit", formId) {
13434
13560
  });
13435
13561
  }
13436
13562
  else{
13563
+ // 这里currentFormValues中如果没有primaryKey字段值不用处理,因为组件的pipeIn/pipeOut中会为每行自动生成
13564
+ // 也不用担心复制行时_id会重复,因为点击复制按钮时已经处理过了
13437
13565
  fieldValue[currentIndex] = currentFormValues;
13438
13566
  }
13439
13567
  doAction({
@@ -13531,6 +13659,7 @@ async function getForm(props, mode = "edit", formId) {
13531
13659
  */
13532
13660
  async function getButtonActions(props, mode) {
13533
13661
  let actions = [];
13662
+ let primaryKey = getTablePrimaryKey(props);
13534
13663
  let formId = getComponentId("form", props.id);
13535
13664
  let dialogId = getComponentId("dialog", props.id);
13536
13665
  let buttonNextId = getComponentId("button_next", props.id);
@@ -13573,13 +13702,35 @@ async function getButtonActions(props, mode) {
13573
13702
  // };
13574
13703
  let onSaveAndNewItemScript = `
13575
13704
  let scope = event.context.scoped;
13705
+ let removeEmptyItems = function(items){
13706
+ let i = _.findIndex(items, function(item){
13707
+ return item === undefined
13708
+ });
13709
+ if(i > -1){
13710
+ items.splice(i, 1);
13711
+ removeEmptyItems(items);
13712
+ }
13713
+ }
13714
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13715
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13716
+ removeEmptyItems(event.data.__tableItems);
13576
13717
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13577
13718
  // 新建一条空白行并保存到子表组件
13578
13719
  var parent = event.data.__super.parent;
13579
- var primaryKey = "${props.primaryKey}";
13720
+ var primaryKey = "${primaryKey}";
13580
13721
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13581
13722
  return item[primaryKey] == parent[primaryKey];
13582
13723
  });
13724
+ if(parent && __parentIndex < 0){
13725
+ let tableId = "${props.id}";
13726
+ let table = scope.getComponentById(tableId)
13727
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13728
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13729
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13730
+ __parentIndex = _.findIndex(table.props.value, function(item){
13731
+ return item[primaryKey] == parent[primaryKey];
13732
+ });
13733
+ }
13583
13734
  if(parent){
13584
13735
  fieldValue[__parentIndex].children.push({});
13585
13736
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13613,14 +13764,42 @@ async function getButtonActions(props, mode) {
13613
13764
  let __formId = "${formId}";
13614
13765
  // let newItem = JSON.parse(JSON.stringify(event.data));
13615
13766
  let newItem = scope.getComponentById(__formId).getValues();//这里不可以用event.data,因为其拿到的是弹出表单时的初始值,不是用户实时填写的数据
13767
+ newItem = _.clone(newItem);
13768
+ let removeEmptyItems = function(items){
13769
+ let i = _.findIndex(items, function(item){
13770
+ return item === undefined
13771
+ });
13772
+ if(i > -1){
13773
+ items.splice(i, 1);
13774
+ removeEmptyItems(items);
13775
+ }
13776
+ }
13777
+ // 因为删除时只是把input-table组件中的行数据删除了,并没有把父层service中的行删除,所以__tableItems会有值为undefined的数据,需要移除掉
13778
+ // 不用event.data.__tableItems = _.compact(event.data.__tableItems)是因为会把__tableItems变量保存到表单中
13779
+ removeEmptyItems(event.data.__tableItems);
13616
13780
  let fieldValue = event.data.__tableItems;//这里不可以_.cloneDeep,因为翻页form中用的是event.data.__tableItems,直接变更其值即可改变表单中的值
13617
13781
  // 复制当前页数据到新建行并保存到子表组件
13618
13782
  // fieldValue.push(newItem);
13619
13783
  var parent = event.data.__super.parent;
13620
- var primaryKey = "${props.primaryKey}";
13784
+ var primaryKey = "${primaryKey}";
13621
13785
  var __parentIndex = parent && _.findIndex(fieldValue, function(item){
13622
13786
  return item[primaryKey] == parent[primaryKey];
13623
13787
  });
13788
+ if(parent && __parentIndex < 0){
13789
+ let tableId = "${props.id}";
13790
+ let table = scope.getComponentById(tableId)
13791
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
13792
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
13793
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
13794
+ __parentIndex = _.findIndex(table.props.value, function(item){
13795
+ return item[primaryKey] == parent[primaryKey];
13796
+ });
13797
+ }
13798
+ if(newItem[primaryKey]){
13799
+ // 如果newItem已经有主键字段值,则重新生成新的主键值,否则会重复。
13800
+ let uuidv4 = new Function("return (" + ${uuidv4.toString()} + ")()");
13801
+ newItem[primaryKey] = uuidv4();
13802
+ }
13624
13803
  if(parent){
13625
13804
  fieldValue[__parentIndex].children.push(newItem);
13626
13805
  // 这里实测不需要fieldValue[__parentIndex] = ... 来重写整个父行让子表回显,所以没加相关代码
@@ -13828,7 +14007,10 @@ async function getButtonActions(props, mode) {
13828
14007
  // 为了解决"弹出的dialog窗口中子表组件会影响页面布局界面中父作用域字段值",比如设计字段布局微页面中的设置分组功能,弹出的就是子表dialog
13829
14008
  // 所以这里使用json|toJson转一次,断掉event.data.__tableItems与上层任用域中props.name的联系
13830
14009
  // "__tableItems": `\${${props.name}|json|toJson}`
13831
- "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
14010
+ // "__tableItems": `\${((__super.parent ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
14011
+ // 在节点嵌套情况下,当前节点正好是带children属性的节点的话,这里弹出的dialog映射到的会是children数组,这是amis目前的规则,
14012
+ // 所以这里加判断有children时,用__super.__super让映射到正确的作用域层,如果不加,则__tableItems取到的会是children数组,而不是整个子表组件的值
14013
+ "__tableItems": `\${((children ? __super.__super.${props.name} : __super.${props.name}) || [])|json|toJson}`
13832
14014
  },
13833
14015
  }
13834
14016
  }
@@ -13844,13 +14026,24 @@ async function getButtonActions(props, mode) {
13844
14026
  let wrapperServiceData = wrapperService.getData();
13845
14027
  // 这里不可以用event.data["${props.name}"]因为amis input talbe有一层单独的作用域,其值会延迟一拍
13846
14028
  // 这里_.clone是因为字段设计布局设置分组这种弹出窗口中的子表组件,直接删除后,点取消无法还原
14029
+ // 也因为这里clone没有直接删除,所以弹出编辑表单提交事件中event.data.__tableItems中取到的值会有被删除的行数据为undefined
13847
14030
  let lastestFieldValue = _.clone(wrapperServiceData["${props.name}"]);
13848
14031
  var currentIndex = event.data.index;
13849
14032
  var parent = event.data.__super.parent;
13850
- var primaryKey = "${props.primaryKey}";
14033
+ var primaryKey = "${primaryKey}";
13851
14034
  var __parentIndex = parent && _.findIndex(lastestFieldValue, function(item){
13852
14035
  return item[primaryKey] == parent[primaryKey];
13853
14036
  });
14037
+ if(parent && __parentIndex < 0){
14038
+ let tableId = "${props.id}";
14039
+ let table = scope.getComponentById(tableId)
14040
+ // autoGeneratePrimaryKeyValue不为true的情况下,即子表组件input-table的pipeOut函数中会移除表单了子表字段的primaryKey字段值,
14041
+ // 此时行primaryKey字段值为空,但是pipeIn函数中已经为input-table自动生成过primaryKey字段值了,只是没有输出到表单字段值中而已
14042
+ // 所以上面从表单字段值中没找到__parentIndex,是因为此时行primaryKey字段值只经过pipeIn保存到table组件内而没有保存到tableService
14043
+ __parentIndex = _.findIndex(table.props.value, function(item){
14044
+ return item[primaryKey] == parent[primaryKey];
14045
+ });
14046
+ }
13854
14047
  if(parent){
13855
14048
  lastestFieldValue[__parentIndex].children.splice(currentIndex, 1);
13856
14049
  // 重写父节点,并且改变其某个属性以让子节点修改的内容回显到界面上
@@ -13862,6 +14055,11 @@ async function getButtonActions(props, mode) {
13862
14055
  else{
13863
14056
  lastestFieldValue.splice(currentIndex, 1);
13864
14057
  }
14058
+ let fieldPrefix = "${props.fieldPrefix || ''}";
14059
+ if(fieldPrefix){
14060
+ let getTableValueWithoutFieldPrefix = new Function('v', 'f', "return (" + ${getTableValueWithoutFieldPrefix.toString()} + ")(v, f)");
14061
+ lastestFieldValue = getTableValueWithoutFieldPrefix(lastestFieldValue, fieldPrefix);
14062
+ }
13865
14063
  doAction({
13866
14064
  "componentId": "${props.id}",
13867
14065
  "actionType": "setValue",
@@ -13947,16 +14145,15 @@ const getAmisInputTableSchema = async (props) => {
13947
14145
  if (!props.id) {
13948
14146
  props.id = "steedos_input_table_" + props.name + "_" + Math.random().toString(36).substr(2, 9);
13949
14147
  }
13950
- if (!props.primaryKey) {
13951
- props.primaryKey = "_id";
13952
- }
14148
+ let primaryKey = getTablePrimaryKey(props);
13953
14149
  let showOperation = props.showOperation;
13954
14150
  if(showOperation !== false){
13955
14151
  showOperation = true;
13956
14152
  }
13957
- // props.fieldPrefix = "project_milestone_";
13958
- if (props.fieldPrefix) {
13959
- props.fields = getTableFieldsWithoutFieldPrefix(props.fields, props.fieldPrefix);
14153
+ let fieldPrefix = props.fieldPrefix;
14154
+ let fields = props.fields || [];
14155
+ if (fieldPrefix) {
14156
+ fields = getTableFieldsWithoutFieldPrefix(fields, fieldPrefix);
13960
14157
  }
13961
14158
  let serviceId = getComponentId("table_service", props.id);
13962
14159
  let buttonsForColumnOperations = [];
@@ -13969,7 +14166,7 @@ const getAmisInputTableSchema = async (props) => {
13969
14166
  // 始终显示弹出子表表单按钮,如果需要判断只在有列被隐藏时才需要显示弹出表单按钮放开下面的if逻辑就好
13970
14167
  showEditButton = true;
13971
14168
  // // inline edit模式下只在有列被隐藏时才需要显示编辑按钮
13972
- // if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length) {
14169
+ // if (props.columns && props.columns.length > 0 && props.columns.length < fields.length) {
13973
14170
  // showEditButton = true;
13974
14171
  // }
13975
14172
  // else {
@@ -13984,7 +14181,7 @@ const getAmisInputTableSchema = async (props) => {
13984
14181
  }
13985
14182
  else {
13986
14183
  // 只读时显示查看按钮
13987
- // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < props.fields.length)
14184
+ // 如果想只在有列被隐藏时才需要显示查看按钮可以加上判断:if (props.columns && props.columns.length > 0 && props.columns.length < fields.length)
13988
14185
  let buttonViewSchema = await getButtonView(props);
13989
14186
  buttonsForColumnOperations.push(buttonViewSchema);
13990
14187
  }
@@ -13993,10 +14190,10 @@ const getAmisInputTableSchema = async (props) => {
13993
14190
  buttonsForColumnOperations.push(buttonDeleteSchema);
13994
14191
  }
13995
14192
  }
13996
- let amis = props["input-table"] || props.amis;//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
14193
+ let amis = props["input-table"] || props.amis || {};//额外支持"input-table"代替amis属性,是因为在字段yml文件中用amis作为key不好理解
13997
14194
  let inputTableSchema = {
13998
14195
  "type": "input-table",
13999
- "label": props.label,
14196
+ "mode": "normal",
14000
14197
  "name": props.name,
14001
14198
  //不可以addable/editable/removable设置为true,因为会在原生的操作列显示操作按钮图标,此开关实测只控制这个按钮显示不会影响功能
14002
14199
  // "addable": props.addable,
@@ -14012,13 +14209,42 @@ const getAmisInputTableSchema = async (props) => {
14012
14209
  "showTableAddBtn": false,
14013
14210
  "showFooterAddBtn": false,
14014
14211
  "className": props.tableClassName,
14212
+ "pipeIn": (value, data) => {
14213
+ if(fieldPrefix){
14214
+ value = getTableValueWithoutFieldPrefix(value, fieldPrefix);
14215
+ }
14216
+ if(primaryKey){
14217
+ // 这里临时给每行数据补上primaryKey字段值,如果库里不需要保存这里补上的字段值,pipeOut中会识别autoGeneratePrimaryKeyValue属性选择最终移除这里补上的字段值
14218
+ // 这里始终自动生成primaryKey字段值,而不是只在pipeOut输出整个子表字段值时才生成,是因为要支持当数据库里保存的子表字段行数据没有primaryKey字段值时的行嵌套模式(即节点的children属性)功能
14219
+ // 这里要注意,流程详细设置界面的字段设置功能中的子表组件中,数据库里保存的子表字段行数据是有primaryKey字段值的,它不依赖这里自动生成行primaryKey值功能
14220
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14221
+ }
14222
+ if(amis.pipeIn){
14223
+ if(typeof amis.pipeIn === 'function'){
14224
+ return amis.pipeIn(value, data);
14225
+ }
14226
+ }
14227
+ return value;
14228
+ },
14015
14229
  "pipeOut": (value, data) => {
14016
14230
  value = (value || []).map(function(item){
14017
14231
  delete item.__fix_rerender_after_children_modified_tag;
14018
14232
  return item;
14019
14233
  });
14020
- if(props.fieldPrefix){
14021
- value = getTableValuePrependFieldPrefix(value, props.fieldPrefix);
14234
+ if(fieldPrefix){
14235
+ value = getTableValuePrependFieldPrefix(value, fieldPrefix, primaryKey);
14236
+ }
14237
+ if(props.autoGeneratePrimaryKeyValue === true){
14238
+ // 如果需要把自动生成的primaryKey值输出保存的库中,则补全所有行中的primaryKey值
14239
+ // 这里如果不全部补全的话,初始从库里返回的字段值中拿到的行没primaryKey值的话就不会自动补上
14240
+ value = getTableValueWithPrimaryKeyValue(value, primaryKey);
14241
+ }
14242
+ else {
14243
+ // 默认情况下,也就是没有配置autoGeneratePrimaryKey时,最终输出的字段值要移除行中的primaryKey值
14244
+ // 需要注意如果没有配置autoGeneratePrimaryKey时,因为每次弹出行编辑窗口保存后都会先后进入pipeOut和pipeIn,
14245
+ // 这里删除掉了primaryKey值,所以primaryKey值每次弹出编辑窗口保存后都会给每行重新生成新的primaryKey值
14246
+ // 只有autoGeneratePrimaryKey配置为true时,每行的primaryKey字段值才会始终保持不变
14247
+ value = getTableValueWithoutPrimaryKeyValue(value, primaryKey);
14022
14248
  }
14023
14249
  if(amis.pipeOut){
14024
14250
  if(typeof amis.pipeOut === 'function'){
@@ -14028,20 +14254,6 @@ const getAmisInputTableSchema = async (props) => {
14028
14254
  return value;
14029
14255
  }
14030
14256
  };
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
14257
  if (buttonsForColumnOperations.length) {
14046
14258
  inputTableSchema.columns.push({
14047
14259
  "name": "__op__",
@@ -14060,7 +14272,7 @@ const getAmisInputTableSchema = async (props) => {
14060
14272
  delete amis.pipeOut;//该属性在上面合并过了
14061
14273
  Object.assign(inputTableSchema, amis);
14062
14274
  }
14063
- const isAnyFieldHasDependOn = (props.fields || []).find(function (item) {
14275
+ const isAnyFieldHasDependOn = (fields || []).find(function (item) {
14064
14276
  return item.depend_on;
14065
14277
  });
14066
14278
  if (isAnyFieldHasDependOn) {
@@ -14095,7 +14307,16 @@ const getAmisInputTableSchema = async (props) => {
14095
14307
  }
14096
14308
  let schema = {
14097
14309
  "type": "service",
14098
- "body": schemaBody,
14310
+ "body": [
14311
+ {
14312
+ "type": "control",
14313
+ "body": schemaBody,
14314
+ "label": props.label,
14315
+ "labelClassName": props.label ? props.labelClassName : "none",
14316
+ "labelRemark": props.labelRemark,
14317
+ "labelAlign": props.labelAlign
14318
+ }
14319
+ ],
14099
14320
  "className": props.className,
14100
14321
  "id": serviceId
14101
14322
  };