@steedos-widgets/amis-object 1.2.13 → 1.2.15

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.
@@ -1745,8 +1745,8 @@ const parseSingleExpression$1 = function (func, formData, dataPath, global, user
1745
1745
  /*
1746
1746
  * @Author: baozhoutao@steedos.com
1747
1747
  * @Date: 2022-11-01 15:51:00
1748
- * @LastEditors: Please set LastEditors
1749
- * @LastEditTime: 2023-04-26 11:52:04
1748
+ * @LastEditors: liaodaxue
1749
+ * @LastEditTime: 2023-06-06 11:12:33
1750
1750
  * @Description:
1751
1751
  */
1752
1752
 
@@ -1829,7 +1829,7 @@ const getSchema$4 = async (uiSchema, ctx) => {
1829
1829
  "isLookup": "${isLookup}",
1830
1830
  "listName": "${listName}"
1831
1831
  },
1832
- "title": "新建 ${uiSchema.label}",
1832
+ "title": "新建 ${uiSchema.label | raw}",
1833
1833
  "body": [
1834
1834
  {
1835
1835
  "type": "service",
@@ -5802,6 +5802,7 @@ async function lookupToAmisPicker(field, readonly, ctx){
5802
5802
  pickerSchema = await getTableSchema$1(tableFields, {
5803
5803
  labelFieldName: refObjectConfig.NAME_FIELD_KEY,
5804
5804
  top: top,
5805
+ isLookup: true,
5805
5806
  ...ctx
5806
5807
  });
5807
5808
 
@@ -5851,6 +5852,10 @@ async function lookupToAmisPicker(field, readonly, ctx){
5851
5852
  };
5852
5853
  }
5853
5854
 
5855
+ if(field.pickerSchema){
5856
+ pickerSchema = Object.assign({}, pickerSchema, field.pickerSchema);
5857
+ }
5858
+
5854
5859
  const data = {
5855
5860
  type: getAmisStaticFieldType('picker', readonly),
5856
5861
  labelField: referenceTo.labelField.name,
@@ -6377,7 +6382,7 @@ const getAmisFileReadonlySchema = (steedosField)=>{
6377
6382
  return {
6378
6383
  type: amisFieldType,
6379
6384
  tpl: `
6380
- <% let fileData = data.${steedosField.name}; if (fileData) { %>
6385
+ <% let fileData = data._display.${steedosField.name}; if (fileData) { %>
6381
6386
  <% if(!Array.isArray(fileData)){ fileData = [fileData]} %>
6382
6387
  <% fileData.forEach(function(item) { %>
6383
6388
  <a href='<%= item.url %>' target='_self' class='block'><%= item.name %></a>
@@ -6418,7 +6423,6 @@ const getAmisFileEditSchema = (steedosField)=>{
6418
6423
  }
6419
6424
  }
6420
6425
  };
6421
-
6422
6426
  if(steedosField.multiple){
6423
6427
  convertData.multiple = true;
6424
6428
  convertData.joinValues = false;
@@ -7141,2204 +7145,2439 @@ var index = /*#__PURE__*/Object.freeze({
7141
7145
  getAmisStaticFieldType: getAmisStaticFieldType
7142
7146
  });
7143
7147
 
7144
- const API_CACHE = 100;
7148
+ /*
7149
+ * @Author: baozhoutao@steedos.com
7150
+ * @Date: 2022-08-04 10:42:49
7151
+ * @LastEditors: baozhoutao@steedos.com
7152
+ * @LastEditTime: 2022-08-25 10:28:47
7153
+ * @Description:
7154
+ */
7155
+ var config = {
7156
+ listView: {
7157
+ newRecordMode: 'modal',
7158
+ editRecordMode: 'modal',
7159
+ perPage: 20
7160
+ }
7161
+ };
7145
7162
 
7146
- function getReadonlyFormAdaptor(object, fields){
7147
- let scriptStr = '';
7148
- const selectFields = ___default.filter(fields, function(field){return field.name.indexOf('.') < 0 && ((field.type == 'select' && field.options) || ((field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to))});
7149
- const gridAndObjectFieldsName = ___default.map(___default.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type === 'object' || field.type === 'grid')}), 'name');
7150
- ___default.each(selectFields, function(field){
7151
- if(!___default.includes(OMIT_FIELDS, field.name)){
7152
- field.name;
7153
- if(field.options){
7154
- const options = JSON.stringify({options: field.options});
7155
- scriptStr = scriptStr + `var ${field.name}Options= (${options}).options;`;
7156
- }else if(field.optionsFunction){
7157
- scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`;
7158
- }else if(field._optionsFunction){
7159
- scriptStr = scriptStr + `var ${field.name}Options = eval(${field._optionsFunction})(api.data);`;
7160
- }
7161
- if(field.multiple){
7162
- scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`;
7163
- }else {
7164
- scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`;
7165
- scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`;
7163
+ async function getQuickEditSchema(field, options){
7164
+ const quickEditId = options.objectName + "_" + field.name + "QuickEdit";//定义快速编辑的表单id,用于setvalue传值
7165
+ var quickEditSchema = { body: [], id: quickEditId };
7166
+ if (field.disabled) {
7167
+ quickEditSchema = false;
7168
+ } else {
7169
+ var fieldSchema = await convertSFieldToAmisField(field, false, ___default.omit(options, 'buttons'));
7170
+ //存在属性上可编辑,实际不可编辑的字段,convertSFieldToAmisField函数可能会返回undefined,如summary
7171
+ if (!!fieldSchema) {
7172
+ quickEditSchema.body.push(fieldSchema);
7173
+ //以下字段使用_display的数据,因此在触发change等事件时对数据_display进行修改,以实现保存前的回显
7174
+ var TempDisplayField = ``;
7175
+ quickEditSchema.body[0].onEvent = {};
7176
+ const quickEditOnEvent = function (displayField) {
7177
+ const EventType = {
7178
+ "actions": [
7179
+ {
7180
+ "actionType": "custom",
7181
+ "script": `
7182
+ var _display = event.data._display;
7183
+ ${displayField}
7184
+ doAction({actionType: 'setValue', "args": {"value": {_display}},componentId: "${quickEditId}"});
7185
+ `
7186
+ }
7187
+ ]
7188
+ };
7189
+ return EventType;
7190
+ };
7191
+ switch (field.type) {
7192
+ //TODO:amis的picker组件直接点击选项x时不会触发change事件,待处理
7193
+ case "lookup":
7194
+ case "master_detail":
7195
+ if (field.multiple) {
7196
+ TempDisplayField = `
7197
+ _display["${field.name}"] = [];
7198
+ event.data.value.forEach(function(item,index){
7199
+ _display["${field.name}"].push(
7200
+ {
7201
+ "label": event.data.option[index].${quickEditSchema.body[0].labelField},
7202
+ "value": event.data.option[index]._id,
7203
+ "objectName": "${field.reference_to}"
7204
+ }
7205
+ )
7206
+ })
7207
+ `;
7208
+ } else {
7209
+ TempDisplayField = `
7210
+ _display["${field.name}"] = {
7211
+ "label": event.data.option.${quickEditSchema.body[0].labelField},
7212
+ "value": event.data._id,
7213
+ "objectName": "${field.reference_to}"
7214
+ }
7215
+ `;
7216
+ }
7217
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7218
+ break;
7219
+ case "select":
7220
+ TempDisplayField = `
7221
+ _display["${field.name}"] = event.data.selectedItems.label;
7222
+ `;
7223
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7224
+ break;
7225
+ case "percent":
7226
+ TempDisplayField = `
7227
+ _display["${field.name}"] = (event.data.value * 100).toFixed(${field.scale}) + '%';
7228
+ `;
7229
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7230
+ break;
7231
+ case "time":
7232
+ TempDisplayField = `
7233
+ _display["${field.name}"] = moment(event.data.value).utc().format('HH:mm');
7234
+ `;
7235
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7236
+ break;
7237
+ case "date":
7238
+ TempDisplayField = `
7239
+ _display["${field.name}"] = moment(event.data.value).utc().format('YYYY-MM-DD');
7240
+ `;
7241
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7242
+ break;
7243
+ case "datetime":
7244
+ TempDisplayField = `
7245
+ _display["${field.name}"] = moment(event.data.value).format('YYYY-MM-DD HH:mm');
7246
+ `;
7247
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7248
+ break;
7249
+ case "boolean":
7250
+ TempDisplayField = `
7251
+ _display["${field.name}"] = event.data.value?"√":"";
7252
+ `;
7253
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7254
+ break;
7255
+ case "number":
7256
+ case "currency":
7257
+ TempDisplayField = `
7258
+ _display["${field.name}"] = event.data.value?.toFixed(${field.scale});
7259
+ `;
7260
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
7261
+
7262
+ break;
7263
+ case "file":
7264
+ var removeDisplayField = ``;
7265
+ if (field.multiple) {
7266
+ TempDisplayField = `
7267
+ _display["${field.name}"].push({
7268
+ "name": event.data.result.name,
7269
+ "url": event.data.result.url,
7270
+ "type": event.data.item.type,
7271
+ "size": event.data.item.size
7272
+ });
7273
+ `;
7274
+ removeDisplayField = `
7275
+ _.remove(_display["${field.name}"], function(file){return file.url == event.data.item.url});
7276
+ `;
7277
+ } else {
7278
+ TempDisplayField = `
7279
+ _display["${field.name}"] = {
7280
+ "name": event.data.result.name,
7281
+ "url": event.data.result.url,
7282
+ "type": event.data.item.type,
7283
+ "size": event.data.item.size
7284
+ };
7285
+ `;
7286
+ removeDisplayField = `
7287
+ if(_display["${field.name}"].url == event.data.item.url){
7288
+ _display["${field.name}"] = {};
7289
+ }
7290
+ `;
7291
+ }
7292
+ quickEditSchema.body[0].onEvent["success"] = quickEditOnEvent(TempDisplayField);
7293
+ quickEditSchema.body[0].onEvent["remove"] = quickEditOnEvent(removeDisplayField);
7294
+ break;
7295
+ case "avatar":
7296
+ case "image":
7297
+ quickEditSchema.body[0].receiver.adaptor = `
7298
+ const { context } = api.body;
7299
+ var rootUrl = context.rootUrl + "/api/files/${field.type}s/";
7300
+ payload = {
7301
+ status: response.status == 200 ? 0 : response.status,
7302
+ msg: response.statusText,
7303
+ data: {
7304
+ value: rootUrl + payload._id,//为了实现图片crud的回显,需要将value从id改为url,当保存数据数据时,再在发送适配器内重新将id提取出来
7305
+ name: payload.original.name,
7306
+ url: rootUrl + payload._id,
7307
+ }
7308
+ }
7309
+ return payload;
7310
+ `;
7311
+ break;
7166
7312
  }
7167
- }
7168
- });
7169
-
7170
- // const refFields = _.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to});
7171
- // _.each(refFields, function(field){
7172
- // if(!_.includes(OMIT_FIELDS, field.name)){
7173
- // const valueField = field.reference_to_field || '_id';
7174
- // scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`
7175
- // if(field.multiple){
7176
- // scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`
7177
- // }else{
7178
- // scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`
7179
- // scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`
7180
- // }
7181
- // }
7182
- // })
7183
7313
 
7184
- return `
7185
- if(payload.data.data.length === 0){
7186
- return {
7187
- status: 2,
7188
- msg: "无法找到记录"
7189
- }
7190
- }
7191
- if(payload.data.data){
7192
- var data = payload.data.data[0];
7193
- var gridAndObjectFieldsName = ${JSON.stringify(gridAndObjectFieldsName)};
7194
- try{
7195
- ${scriptStr}
7196
- ${getScriptForAddUrlPrefixForImgFields(fields)}
7197
- ${getScriptForRewriteValueForFileFields(fields)}
7198
- }catch(e){
7199
- console.error(e)
7314
+ } else {
7315
+ quickEditSchema = false;
7200
7316
  }
7201
- // 原始记录
7202
- var record = _.cloneDeep(data);
7203
- try{
7204
- _.each(gridAndObjectFieldsName, function(name){
7205
- data[name] = data._display[name];
7206
- })
7207
- }catch(e){
7208
- console.error(e)
7317
+ //TODO:附件多选时会覆盖老数据,暂时禁用
7318
+ if(field.type == "file" && field.multiple){
7319
+ quickEditSchema = false;
7209
7320
  }
7210
- payload.data = data;
7211
- payload.data.__objectName = "${object.name}";
7212
- payload.data.__record = record;
7213
- window.postMessage(Object.assign({type: "record.loaded"}, {record: record}), "*")
7214
7321
  }
7215
- if(payload.errors){
7216
- payload.status = 2;
7217
- payload.msg = payload.errors[0].message;
7218
- }
7219
- return payload;
7220
- `
7322
+ return quickEditSchema;
7221
7323
  }
7222
7324
 
7223
- async function getReadonlyFormInitApi(object, recordId, fields, options){
7224
- return {
7225
- method: "post",
7226
- url: getApi$2()+"&recordId=${recordId}",
7227
- cache: API_CACHE,
7228
- // requestAdaptor: "console.log('getReadonlyFormInitApi requestAdaptor', api);return api;",
7229
- adaptor: getReadonlyFormAdaptor(object, fields),
7230
- data: await getFindOneQuery$1(object, recordId, fields, options),
7231
- headers: {
7232
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7325
+ async function getTableColumns$1(fields, options){
7326
+ const columns = [{name: '_index',type: 'text', width: 32, placeholder: ""}];
7327
+ const allowEdit = options.permissions?.allowEdit && options.permissions?.modifyAllRecords && !options.isLookup && options.enable_inline_edit != false;
7328
+ for (const field of fields) {
7329
+ //增加quickEdit属性,实现快速编辑
7330
+ const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
7331
+ if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
7332
+ const previewFileScript = `
7333
+ var data = event.data;
7334
+ var file_name = data.versions ? data.name : "${field.label}";
7335
+ var file_id = data._id;
7336
+ SteedosUI.previewFile && SteedosUI.previewFile({file_name, file_id});
7337
+ `;
7338
+ columns.push({
7339
+ "type": "button",
7340
+ "label": `<%=data.versions ? data.name : "${field.label}"%>`,
7341
+ "className": "whitespace-nowrap",
7342
+ "level": "link",
7343
+ "quickEdit": quickEditSchema,
7344
+ "onEvent": {
7345
+ "click": {
7346
+ "actions": [
7347
+ {
7348
+ "args": {
7349
+ "api": {
7350
+ "url": "${context.rootUrl}/api/files/files/${versions[0]}?download=true",
7351
+ "method": "get",
7352
+ "headers": {
7353
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
7354
+ }
7355
+ }
7356
+ },
7357
+ "actionType": "download",
7358
+ "expression": "!!!window?.nw?.require"//浏览器上直接下载
7359
+ },
7360
+ {
7361
+ "args": {},
7362
+ "actionType": "custom",
7363
+ "script": previewFileScript,
7364
+ "expression": "!!window?.nw?.require" //PC客户端预览附件
7365
+ }
7366
+ ]
7367
+ }
7368
+ }
7369
+ });
7370
+ }else if(field.type === 'toggle'){
7371
+ columns.push(Object.assign({}, {
7372
+ type: "switch",
7373
+ name: field.name,
7374
+ label: field.label,
7375
+ width: field.width,
7376
+ toggled: field.toggled,
7377
+ className:"whitespace-nowrap"
7378
+ }, field.amis, {name: field.name}));
7379
+ }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7380
+ columns.push(Object.assign({}, {
7381
+ type: "switch",
7382
+ name: field.name,
7383
+ label: field.label,
7384
+ width: field.width,
7385
+ toggled: field.toggled,
7386
+ quickEdit: quickEditSchema,
7387
+ className:"whitespace-nowrap",
7388
+ ...getAmisFileReadonlySchema(field)
7389
+ }, field.amis, {name: field.name}));
7390
+ }
7391
+ else if(field.type === 'select'){
7392
+ const map = getSelectMap(field.options);
7393
+ columns.push(Object.assign({}, {
7394
+ type: "mapping",
7395
+ name: field.name,
7396
+ label: field.label,
7397
+ map: map,
7398
+ sortable: field.sortable,
7399
+ width: field.width,
7400
+ toggled: field.toggled,
7401
+ className:"whitespace-nowrap",
7402
+ quickEdit: quickEditSchema
7403
+ }, field.amis, {name: field.name}));
7233
7404
  }
7405
+ else {
7406
+ const tpl = await getFieldTpl(field, options);
7407
+ let type = 'text';
7408
+ if(tpl){
7409
+ type = 'tpl';
7410
+ }else if(field.type === 'html'){
7411
+ type = 'markdown';
7412
+ }else if(field.type === 'url' && field.show_as_qr){
7413
+ type = 'qr-code';
7414
+ }
7415
+ let className = "";
7416
+ if(field.type === 'textarea'){
7417
+ className = 'min-w-56';
7418
+ }
7419
+ if(field.wrap === false){
7420
+ className += " whitespace-nowrap";
7421
+ }
7422
+ if(!field.hidden && !field.extra){
7423
+ columns.push(Object.assign({}, {
7424
+ name: field.name,
7425
+ label: field.label,
7426
+ sortable: field.sortable,
7427
+ // searchable: field.searchable,
7428
+ width: field.width,
7429
+ type: type,
7430
+ tpl: tpl,
7431
+ toggled: field.toggled,
7432
+ className,
7433
+ quickEdit: quickEditSchema,
7434
+ options: field.type === 'html' ? {html: true} : null
7435
+ // toggled: true
7436
+ }, field.amis, {name: field.name}));
7437
+ }
7438
+ }
7439
+ }
7440
+ // columns.push(getOperation(fields));
7441
+ if(!___default.some(columns, { name: options.labelFieldName })){
7442
+ const href = Router$1.getObjectDetailPath({
7443
+ ...options, formFactor: options.formFactor, appId: "${appId}", objectName: options.objectName || "${objectName}", recordId: `\${${options.idFieldName}}`
7444
+ });
7445
+ columns[0].type = "tpl";
7446
+ columns[0].tpl = `<a href="${href}">\${${columns[0].name}}</a>`;
7234
7447
  }
7448
+ return columns;
7235
7449
  }
7236
7450
 
7237
- /*
7238
- img/avatar字段值添加URL前缀使其在amis中正常显示图片。
7239
- */
7240
- function getScriptForAddUrlPrefixForImgFields(fields){
7241
- let imgFieldsKeys = [];
7242
- let imgFields = {};
7243
- fields.forEach((item)=>{
7244
- if(___default.includes(['image','avatar'], item.type)){
7245
- imgFieldsKeys.push(item.name);
7246
- imgFields[item.name] = {
7247
- name: item.name,
7248
- type: item.type,
7249
- multiple: item.multiple
7250
- };
7251
- }
7252
- });
7253
- if(!imgFieldsKeys.length){
7254
- return '';
7255
- }
7256
- return `
7257
- // image字段值添加URL前缀
7258
- let imgFieldsKeys = ${JSON.stringify(imgFieldsKeys)};
7259
- let imgFields = ${JSON.stringify(imgFields)};
7260
- imgFieldsKeys.forEach((item)=>{
7261
- let imgFieldValue = data[item];
7262
- let imgFieldDisplayValue = data._display && data._display[item];
7263
- if(imgFieldValue && imgFieldValue.length){
7264
- let fieldProps = imgFields[item];
7265
- if(fieldProps.multiple){
7266
- if(imgFieldDisplayValue instanceof Array){
7267
- data[item] = imgFieldDisplayValue.map((i)=>{ return i.url });
7268
- }
7269
- }else{
7270
- data[item] = imgFieldDisplayValue && imgFieldDisplayValue.url;
7271
- }
7272
- }
7273
- })
7274
- `
7275
- }
7451
+ /**
7452
+ * 生成移动端列表每行显示的amis
7453
+ * @param {*} tpls 要显示的每个字段的tpl
7454
+ * @returns {
7455
+ "type": "wrapper",
7456
+ "body": [{
7457
+ "type": "tpl",
7458
+ "tpl": tpls[index].tpl,
7459
+ "className": "truncate"//左侧样式类
7460
+ },{
7461
+ "type": "tpl",
7462
+ "tpl": tpls[index + 1].tpl,
7463
+ "className": "truncate ml-2 flex flex-shrink-0"//右侧样式类
7464
+ }],
7465
+ "size": "none",
7466
+ "className": "flex items-center justify-between"//每行样式类
7467
+ }
7468
+ */
7469
+ function getMobileLines(tpls){
7470
+ let lines = [];
7471
+ let maxLineCount = 2;
7472
+ let lineChildren = [];
7473
+ let isNewLine = false;
7474
+ let isLeft = true;
7475
+ let lineChildrenClassName = "";
7476
+ let lineClassName = "flex items-center justify-between h-[20px]";
7477
+ tpls.forEach(function(item){
7478
+ if(isNewLine && lines.length < maxLineCount){
7479
+ lines.push({
7480
+ "type": "wrapper",
7481
+ "body": lineChildren,
7482
+ "size": "none",
7483
+ "className": lineClassName
7484
+ });
7485
+ lineChildren = [];
7486
+ }
7487
+ if(isLeft){
7488
+ // 左侧半行
7489
+ lineChildrenClassName = "steedos-listview-item-left truncate";
7490
+ if(item.field.is_wide){
7491
+ // 左侧全行样式可以单独写
7492
+ lineChildrenClassName = "steedos-listview-item-wide truncate";
7493
+ }
7494
+ if(lines.length === 0){
7495
+ // 第一个字段加粗黑色显示
7496
+ lineChildrenClassName += " font-bold text-gray-800";
7497
+ }
7498
+ }
7499
+ else {
7500
+ // 右侧半行
7501
+ lineChildrenClassName = "steedos-listview-item-right truncate ml-2 flex flex-shrink-0";
7502
+ }
7503
+ lineChildren.push({
7504
+ "type": "tpl",
7505
+ "tpl": item.tpl,
7506
+ "className": lineChildrenClassName
7507
+ });
7276
7508
 
7277
- /*
7278
- file字段值重写使其在amis中正常显示附件名、点击附件名下载文件。
7279
- */
7280
- function getScriptForRewriteValueForFileFields(fields){
7281
- let fileFieldsKeys = [];
7282
- let fileFields = {};
7283
- fields.forEach((item)=>{
7284
- if(item.type === 'file'){
7285
- fileFieldsKeys.push(item.name);
7286
- fileFields[item.name] = {
7287
- name: item.name,
7288
- multiple: item.multiple
7289
- };
7509
+ if(item.field.is_wide){
7510
+ // 宽字段占整行
7511
+ isLeft = true;
7512
+ isNewLine = true;
7513
+ }
7514
+ else {
7515
+ isLeft = !isLeft;
7516
+ isNewLine = isLeft;
7290
7517
  }
7291
7518
  });
7292
- if(!fileFieldsKeys.length){
7293
- return '';
7519
+
7520
+ if(lineChildren.length && lines.length < maxLineCount){
7521
+ lines.push({
7522
+ "type": "wrapper",
7523
+ "body": lineChildren,
7524
+ "size": "none",
7525
+ "className": lineClassName
7526
+ });
7294
7527
  }
7295
- return `
7296
- // file字段值重写以便编辑时正常显示附件名、点击附件名正常下载附件
7297
- let fileFieldsKeys = ${JSON.stringify(fileFieldsKeys)};
7298
- let fileFields = ${JSON.stringify(fileFields)};
7299
- fileFieldsKeys.forEach((item)=>{
7300
- let fileFieldValue = data[item];
7301
- let fileFieldDisplayValue = data._display && data._display[item];
7302
- if(fileFieldValue && fileFieldValue.length){
7303
- if(fileFields[item].multiple){
7304
- if(fileFieldDisplayValue instanceof Array){
7305
- data[item] = fileFieldDisplayValue.map((item, index)=>{
7306
- return {
7307
- value: fileFieldValue[index],
7308
- name: item.name,
7309
- url: item.url + "?download=true",
7310
- state: "uploaded"
7311
- }
7312
- });
7313
- }
7314
- }else{
7315
- data[item] = [{
7316
- value: fileFieldValue,
7317
- name: fileFieldDisplayValue.name,
7318
- url: fileFieldDisplayValue.url + "?download=true",
7319
- state: "uploaded"
7320
- }];
7321
- }
7322
- }
7323
- })
7324
- `
7528
+
7529
+ return lines;
7325
7530
  }
7326
7531
 
7327
- async function getEditFormInitApi(object, recordId, fields, options){
7328
- const data = await getFindOneQuery$1(object, recordId, fields);
7329
- data.recordId = "${recordId}";
7330
- data.objectName = "${objectName}";
7331
- data.uiSchema = "${uiSchema}";
7332
- data.global = "${global}";
7333
- data.context = "${context}";
7334
- data.defaultData = "${defaultData}";
7335
- data._master = "${_master}";
7336
-
7337
- return {
7338
- method: "post",
7339
- url: getApi$2() + '&objectName=${objectName}' ,
7340
- // sendOn: "!!this.recordId",
7341
- cache: API_CACHE,
7342
- requestAdaptor: `
7343
- // 所有不想在network请求中发送的数据都应该从data中分离出来,data变量只需要留下query才需要发送出去
7344
- var { recordId, objectName, uiSchema, global, context, ...data} = api.data;
7345
- if(!recordId){
7346
- // 新建则不请求任何数据
7347
- data.query = "{data:" + objectName + "(filters: " + JSON.stringify(["_id", "=", null]) + ", top: 1){_id}}";
7532
+ async function getMobileTableColumns(fields, options){
7533
+ const columns = [];
7534
+ let nameField = {};
7535
+ let tpls = [];
7536
+ for (const field of fields) {
7537
+ let tpl = "";
7538
+ if(field.is_name || field.name === options.labelFieldName){
7539
+ nameField = field;
7540
+ options.onlyDisplayLabel = true;
7541
+ tpl = await getFieldTpl(field, options);
7542
+ }
7543
+ else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7544
+ // 图片和附件类型字段暂时显示为附件名称,后续需要再优化
7545
+ tpl = `\${_display.${field.name}.name}`;
7546
+ }
7547
+ else {
7548
+ if(field.type === 'lookup' || field.type === 'master_detail'){
7549
+ options.onlyDisplayLabel = true;
7348
7550
  }
7349
- api.data = data;
7350
- ${options.initApiRequestAdaptor || ''}
7351
- return api;
7352
- `,
7353
- adaptor: `
7354
- const recordId = api.body.recordId;
7355
- let initialValues={};
7356
- if(recordId && payload.data.data){
7357
- var data = payload.data.data[0];
7358
- const dataKeys = _.keys(data);
7359
- const uiSchema = api.body.uiSchema;
7360
- const fieldKeys = uiSchema && _.keys(uiSchema.fields);
7551
+ tpl = await getFieldTpl(field, options);
7552
+ }
7553
+ if(!tpl){
7554
+ tpl = `\${${field.name}}`;
7555
+ }
7556
+ if(!field.hidden && !field.extra){
7557
+ tpls.push({ field, tpl });
7558
+ }
7559
+ }
7560
+ const url = getNameTplUrl(nameField, options);
7361
7561
 
7362
- if(data){
7363
- ${getScriptForAddUrlPrefixForImgFields(fields)}
7364
- ${getScriptForRewriteValueForFileFields(fields)}
7562
+ const columnLines = getMobileLines(tpls);
7365
7563
 
7366
- _.each(dataKeys, function(key){
7367
- if(fieldKeys.indexOf(key)<0){
7368
- delete data[key];
7369
- }
7370
- })
7371
-
7372
- //初始化接口返回的字段移除字段值为null的字段
7373
- for (key in data){
7374
- if(data[key] === null){
7375
- delete data[key];
7376
- }
7564
+
7565
+ let column = {
7566
+ name: nameField.name,
7567
+ label: nameField.label,
7568
+ sortable: nameField.sortable,
7569
+ type: "button",
7570
+ level: "link",
7571
+ actionType: "link",
7572
+ link: url,
7573
+ innerClassName: "steedos-listview-item block text-gray-500",
7574
+ body: {
7575
+ "type": "wrapper",
7576
+ "body": columnLines,
7577
+ "size": "none",
7578
+ "className": "p-1"
7579
+ }
7580
+ };
7581
+
7582
+ if(options.objectName === 'cms_files'){
7583
+ if(window.Meteor?.isCordova){
7584
+ column = {
7585
+ ...column,
7586
+ actionType: "",
7587
+ link: "",
7588
+ onEvent: {
7589
+ "click": {
7590
+ "actions": [
7591
+ {
7592
+ "script": `
7593
+ let cms_url = "/api/files/files/"+event.data.versions[0]+"?download=true"
7594
+ Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
7595
+ `,
7596
+ "actionType": "custom"
7597
+ }
7598
+ ],
7599
+ "weight": 0
7377
7600
  }
7378
- };
7379
- initialValues = data;
7380
- }
7381
- else{
7382
- var uiSchema = api.body.uiSchema;
7383
- var defaultData = api.body.defaultData;
7384
- var defaultValues = {};
7385
- _.each(uiSchema?.fields, function(field){
7386
- var value = SteedosUI.getFieldDefaultValue(field, api.body.global);
7387
- if(value){
7388
- defaultValues[field.name] = value;
7389
- }
7390
- });
7391
- if(defaultData && _.isObject(defaultData) && !_.isArray(defaultData)){
7392
- defaultValues = Object.assign({}, defaultValues, defaultData)
7393
7601
  }
7394
- if(uiSchema.form){
7395
- try{
7396
- var objectFormConfig = JSON.parse(uiSchema.form);
7397
- var formInitialValuesFun = objectFormConfig.initialValues;
7398
- if(formInitialValuesFun){
7399
- formInitialValuesFun = new Function("return " + formInitialValuesFun)();
7400
- }
7401
- if(typeof formInitialValuesFun === "function"){
7402
- initialValues = formInitialValuesFun.apply({doc: defaultValues || {} , global: api.body.global, master: api.body._master })
7403
- }
7404
- }
7405
- catch(ex){
7406
- console.warn(ex);
7602
+ };
7603
+ }else {
7604
+ column = {
7605
+ ...column,
7606
+ actionType: "",
7607
+ link: "",
7608
+ onEvent: {
7609
+ "click": {
7610
+ "actions": [
7611
+ {
7612
+ "args": {
7613
+ "api": {
7614
+ "url": url,
7615
+ "method": "get",
7616
+ "headers": {
7617
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
7618
+ }
7619
+ }
7620
+ },
7621
+ "actionType": "download"
7622
+ }
7623
+ ],
7624
+ "weight": 0
7407
7625
  }
7408
7626
  }
7409
- if(_.isObject(initialValues)){
7410
- // uiSchema.form.initialValues为函数且执行后为json,则优先取initialValues中的默认值
7411
- initialValues = Object.assign({}, defaultValues, initialValues);
7412
- }
7413
- else{
7414
- initialValues = defaultValues;
7415
- }
7416
- }
7417
- // data下的变量需要在保存接口(getSaveApi)中被删除。
7418
- payload.data = {
7419
- ...initialValues
7420
- }
7421
- ${options.initApiAdaptor || ''}
7422
- return payload;
7423
- `,
7424
- responseData: {
7425
- initialValues: "$$",
7426
- editFormInited: true
7427
- },
7428
- data: data,
7429
- headers: {
7430
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7627
+ };
7431
7628
  }
7629
+
7432
7630
  }
7433
- }
7434
7631
 
7632
+ columns.push(column);
7633
+
7435
7634
 
7436
- function getSaveApi(object, recordId, fields, options){
7437
- return {
7438
- method: 'post',
7439
- url: getApi$2(),
7440
- data: getSaveQuery(object, recordId),
7441
- requestAdaptor: getSaveRequestAdaptor(fields, options),
7442
- responseData: {
7443
- "recordId": "${record._id}"
7444
- },
7445
- adaptor: `
7446
- if(payload.errors){
7447
- payload.status = 2;
7448
- payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
7449
- }
7450
- ${options.apiAdaptor || ''}
7451
- return payload;
7452
- `,
7453
- headers: {
7454
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7455
- }
7456
- }
7635
+ return columns;
7457
7636
  }
7458
7637
 
7459
- function getBatchDelete(objectName){
7638
+ function getDefaultParams(options){
7460
7639
  return {
7461
- method: 'post',
7462
- url: getApi$2(),
7463
- requestAdaptor: `
7464
- var ids = api.data.ids.split(",");
7465
- var deleteArray = [];
7466
- ids.forEach((id,index)=>{
7467
- deleteArray.push(\`delete__\${index}:${objectName}__delete(id: "\${id}")\`);
7468
- })
7469
- api.data = {query: \`mutation{\${deleteArray.join(',')}}\`};
7470
- return api;
7471
- `,
7472
- data: {
7473
- ids: `\${ids}`
7474
- },
7475
- headers: {
7476
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7477
- }
7640
+ perPage: options.top || options.perPage || config.listView.perPage
7478
7641
  }
7479
7642
  }
7480
7643
 
7481
- /*
7482
- * @Author: baozhoutao@steedos.com
7483
- * @Date: 2022-05-26 16:02:08
7484
- * @LastEditors: baozhoutao@steedos.com
7485
- * @LastEditTime: 2023-03-13 16:01:40
7486
- * @Description:
7487
- */
7488
-
7489
- const getFieldSchemaArray = (formFields)=>{
7490
- let fieldSchemaArray = [];
7491
- fieldSchemaArray.length = 0;
7644
+ function getButtonVisibleOn(button){
7645
+ let visible= button.visible;
7492
7646
 
7493
- ___default.forEach(formFields, (field) => {
7494
- if (!field.group || field.group == 'null' || field.group == '-')
7495
- field.group = '通用';
7496
- const fieldName = field.name;
7497
- let isObjectField = /\w+\.\w+/.test(fieldName);
7498
- if (field.type == 'grid' || field.type == 'object') {
7499
- // field.group = field.label
7500
- field.is_wide = true;
7501
- }
7502
-
7503
- if (!isObjectField){
7504
- if(!field.hidden){
7505
- fieldSchemaArray.push(Object.assign({name: fieldName}, field, {permission: {allowEdit: true}}));
7506
- }
7647
+ if(button._visible){
7648
+ visible = button._visible;
7507
7649
  }
7508
- });
7509
- return fieldSchemaArray;
7510
- };
7511
-
7512
- const getSection = async (formFields, permissionFields, fieldSchemaArray, sectionName, ctx) => {
7513
- const sectionFields = ___default.filter(fieldSchemaArray, { 'group': sectionName });
7514
- if(sectionFields.length == ___default.filter(sectionFields, ['hidden', true]).length){
7515
- return ;
7516
- }
7517
-
7518
- const fieldSetBody = [];
7519
-
7520
- for (const perField of sectionFields) {
7521
- let field = perField;
7522
- if(perField.type === 'grid'){
7523
- field = await getGridFieldSubFields(perField, formFields);
7524
- // console.log(`perField.type grid ===> field`, field)
7525
- }else if(perField.type === 'object'){
7526
- field = await getObjectFieldSubFields(perField, formFields);
7527
- // console.log(`perField.type object ===> field`, field)
7528
- }
7529
- if(field.name.indexOf(".") < 0){
7530
- ctx.__formFields = formFields;
7531
- const amisField = await convertSFieldToAmisField(field, field.readonly, ctx);
7532
- // console.log(`${field.name} amisField`, field, amisField)
7533
- if(amisField){
7534
- fieldSetBody.push(amisField);
7535
- }
7536
- }
7537
- }
7538
-
7539
- // fieldSet 已支持显隐控制
7540
- const sectionFieldsVisibleOn = ___default.map(___default.compact(___default.map(fieldSetBody, 'visibleOn')) , (visibleOn)=>{
7541
- return visibleOn;
7542
- });
7543
- const section = {
7544
- "type": "fieldSet",
7545
- "title": sectionName,
7546
- "collapsable": true,
7547
- "body": fieldSetBody,
7548
- };
7549
- if(sectionFieldsVisibleOn.length > 0 && fieldSetBody.length === sectionFieldsVisibleOn.length){
7550
- section.visibleOn = `${sectionFieldsVisibleOn.join(" || ")}`;
7551
- }
7552
- return section
7553
- };
7554
7650
 
7555
- const getSections = async (permissionFields, formFields, ctx) => {
7556
- const fieldSchemaArray = getFieldSchemaArray(formFields);
7557
- const _sections = ___default.groupBy(fieldSchemaArray, 'group');
7558
- const sections = [];
7559
- var sectionHeaderVisibleOn=[];
7560
- for (const key in _sections) {
7561
- const section = await getSection(formFields, permissionFields, fieldSchemaArray, key, ctx);
7562
- if(section.body.length > 0){
7563
- if(section.visibleOn){
7564
- sectionHeaderVisibleOn.push(section.visibleOn);
7565
- }
7566
- sections.push(section);
7651
+ if(isBoolean(visible)){
7652
+ visible = visible.toString();
7567
7653
  }
7568
- }
7569
- /*
7570
- 为了实现只有一个分组时隐藏该分组标题,需要分三种情况(分组如果没有visibleon属性就代表一定显示,有visibleon需要进行判断)
7571
- 1.所有分组中只有一个分组没有visibleon,还需要判断其他有visibleon的分组是否显示,只有其他都不显示时,才需要隐藏标题;反之,有任何一个显示,就不需要隐藏标题
7572
- 2.所有分组都有visibleon
7573
- 2.1 当前分组为隐藏时,标题就设置为隐藏
7574
- 2.2 当前分组为显示时,其他分组只要有一个是显示,就显示该分组标题
7575
- 2.3 当前分组为显示时,其他分组都隐藏,就隐藏该分组标题
7576
- 3.所有分组中有两个以上的分组没有visibleon(这种情况不用处理)
7577
- */
7578
- if(ctx.mode == "edit"){
7579
- if (sections.length - sectionHeaderVisibleOn.length == 1) {
7580
- sections.forEach((section) => {
7581
- section.headingClassName = {
7582
- "hidden": `!(${sectionHeaderVisibleOn.join(" || ") || 'false'})`
7583
- };
7584
- });
7585
- } else if (sections.length == sectionHeaderVisibleOn.length) {
7586
- sections.forEach((section, index) => {
7587
- var tempSectionHeaderVisibleOn = sectionHeaderVisibleOn.slice();
7588
- tempSectionHeaderVisibleOn.splice(index, 1);
7589
- section.headingClassName = {
7590
- "hidden": `!((${tempSectionHeaderVisibleOn.join(" || ") || 'false'}) && ${sectionHeaderVisibleOn[index]})`
7591
- };
7592
- });
7593
- }
7594
- }
7595
-
7596
- return sections;
7597
- };
7598
7654
 
7599
- /*
7600
- * @Author: baozhoutao@steedos.com
7601
- * @Date: 2022-07-07 11:02:29
7602
- * @LastEditors: baozhoutao@steedos.com
7603
- * @LastEditTime: 2023-03-07 17:19:34
7604
- * @Description:
7605
- */
7655
+ if(visible){
7656
+ // if(visible.indexOf("Meteor.") > 0 || visible.indexOf("Creator.") > 0 || visible.indexOf("Session.") > 0){
7657
+ // console.warn('无效的visible', visible)
7658
+ // return 'false';
7659
+ // }
7660
+ if(visible.trim().startsWith('function')){
7661
+ return `${visible}(objectName, typeof _id === 'undefined' ? null: _id, typeof record === 'undefined' ? (typeof recordPermissions === 'undefined' ? {} : recordPermissions) : record.recordPermissions, data)`
7662
+ }
7663
+ return visible;
7664
+ }
7606
7665
 
7607
- async function getFormBody(permissionFields, formFields, ctx){
7608
- return await getSections(permissionFields, formFields, ctx);
7666
+ if(button.type === 'amis_button'){
7667
+ const amisSchema = button.amis_schema;
7668
+ if(amisSchema && amisSchema.body && amisSchema.body.length > 0){
7669
+ const btn1 = amisSchema.body[0];
7670
+ return btn1.visibleOn
7671
+ }
7672
+ }
7609
7673
  }
7610
7674
 
7611
- // lodash的defaultsDeep函数有bug,无法正确合并值为数值的节点,重写修正该函数
7612
- // 源码出处:https://github.com/nodeutils/defaults-deep
7613
- const defaultsDeep = (...args)=>{
7614
- let output = {};
7615
- toArray(args).reverse().forEach(item=> {
7616
- mergeWith(output, item, (objectValue, sourceValue) => {
7617
- return isArray(sourceValue) ? sourceValue : undefined;
7675
+ async function getTableOperation(ctx){
7676
+ const buttons = ctx.buttons;
7677
+ const operationButtons = [];
7678
+ each(buttons, (button)=>{
7679
+ if(isBoolean(button.visible)){
7680
+ button.visible = button.visible.toString();
7681
+ }
7682
+ // operationButtons.push({
7683
+ // type: 'button',
7684
+ // label: button.label,
7685
+ // visibleOn: button.visible ? `${button.visible}` : (button._visible ? `${button._visible}` : null),
7686
+ // onEvent: {
7687
+ // click: {
7688
+ // actions: []
7689
+ // }
7690
+ // }
7691
+ // })
7692
+
7693
+ operationButtons.push({
7694
+ type: 'steedos-object-button',
7695
+ name: button.name,
7696
+ objectName: button.objectName,
7697
+ visibleOn: getButtonVisibleOn(button),
7698
+ className: 'antd-Button--default'
7618
7699
  });
7619
7700
  });
7620
- return output;
7621
- };
7622
-
7623
- function getBulkActions(objectSchema){
7624
- return [
7625
- {
7626
- "type": "button",
7627
- "level": "danger",
7628
- "label": "批量删除",
7629
- "actionType": "ajax",
7630
- "confirmText": "确定要删除吗",
7631
- "className": "hidden",
7632
- "id": "batchDelete",
7633
- "api": getBatchDelete(objectSchema.name),
7634
- }
7635
- // {
7636
- // "label": "批量修改",
7637
- // "actionType": "dialog",
7638
- // "dialog": {
7639
- // "title": "批量编辑",
7640
- // "name": "sample-bulk-edit",
7641
- // "body": {
7642
- // "type": "form",
7643
- // "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample/bulkUpdate2",
7644
- // "controls": [
7645
- // {
7646
- // "type": "hidden",
7647
- // "name": "ids"
7648
- // },
7649
- // {
7650
- // "type": "text",
7651
- // "name": "name",
7652
- // "label": "Name"
7653
- // }
7654
- // ]
7655
- // }
7656
- // }
7657
- // }
7658
- ]
7701
+ if(operationButtons.length < 1){
7702
+ return ;
7703
+ }
7704
+ return {
7705
+ type: 'operation',
7706
+ label: '操作',
7707
+ fixed: 'right',
7708
+ labelClassName: 'text-center',
7709
+ className: 'text-center steedos-listview-operation w-20',
7710
+ buttons: [
7711
+ {
7712
+ "type": "steedos-dropdown-button",
7713
+ "label": "xxx",
7714
+ "buttons": operationButtons,
7715
+ "placement": "bottomRight",
7716
+ "overlayClassName": "shadow !min-w-[160px]",
7717
+ "trigger": ["click"],
7718
+ "id": "u:c2140a365019",
7719
+ onOpenApi: {
7720
+ url: `\${context.rootUrl}/service/api/@\${objectName}/recordPermissions/\${_id}`,
7721
+ method: "get",
7722
+ data: {
7723
+ $: "$$",
7724
+ objectName: "${objectName}",
7725
+ listViewId: "${listViewId}",
7726
+ appId: "${appId}",
7727
+ formFactor: "${formFactor}",
7728
+ context: `\${context}`
7729
+ },
7730
+ headers: {
7731
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7732
+ },
7733
+ adaptor: `
7734
+ payload = {
7735
+ record: {
7736
+ recordPermissions: payload
7737
+ }
7738
+ };
7739
+ return payload;
7740
+ `,
7741
+ }
7742
+ }
7743
+ ]
7744
+ }
7659
7745
  }
7660
7746
 
7661
- async function getObjectCRUD(objectSchema, fields, options){
7662
- // console.time('getObjectCRUD');
7663
- const { top, perPage, showDisplayAs = false, displayAs, crudClassName = "" } = options;
7664
- const nonpaged = objectSchema.paging && objectSchema.paging.enabled === false;
7665
- const isTreeObject = objectSchema.enable_tree;
7666
- const bulkActions = getBulkActions(objectSchema);
7667
- const bodyProps = {
7668
- // toolbar: getToolbar(),
7669
- // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
7670
- headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
7671
- footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
7672
- disableStatistics: options.queryCount === false
7673
- }),
7674
- filter: options.filterVisible !== false && await getObjectFilter(objectSchema, fields, options),
7675
- };
7676
- if(options.formFactor !== 'SMALL' || ["split"].indexOf(options.displayAs) == -1){
7677
- Object.assign(bodyProps, {
7678
- bulkActions: options.bulkActions != false ? bulkActions : false
7679
- });
7747
+ async function getTableSchema$1(fields, options){
7748
+ if(!options){
7749
+ options = {};
7680
7750
  }
7681
- // yml里配置的 不分页和enable_tree:true 优先级最高,组件中输入的top次之。
7682
- options.queryCount = true;
7683
- if(nonpaged || isTreeObject){
7684
- options.top = 50000;
7685
- bodyProps.footerToolbar = [];
7686
- options.queryCount = true; // 禁止翻页的时候, 需要查找总数
7687
- }else if(top){
7688
- bodyProps.footerToolbar = [];
7689
- if(options.isRelated){
7690
- options.queryCount = true;
7691
- }else {
7692
- options.queryCount = false;
7693
- }
7751
+ let columns = [];
7752
+ if(options.formFactor === 'SMALL' || ["split"].indexOf(options.displayAs) > -1){
7753
+ columns = await getMobileTableColumns(fields, options);
7694
7754
  }
7695
- // console.log(`getObjectHeaderToolbar====2===>`, options.filterVisible)
7696
- bodyProps.headerToolbar = getObjectHeaderToolbar(objectSchema, options.formFactor, {
7697
- showDisplayAs,
7698
- hiddenCount: options.queryCount === false,
7699
- headerToolbarItems: options.headerToolbarItems,
7700
- filterVisible: options.filterVisible
7701
- });
7755
+ else {
7756
+ columns = await getTableColumns$1(fields, options);
7757
+ columns.push(await getTableOperation(options));
7758
+ }
7759
+ return {
7760
+ mode: "table",
7761
+ name: "thelist",
7762
+ headerToolbarClassName: "py-2 px-2 border-gray-300 bg-gray-100 border-solid border-b",
7763
+ className: "",
7764
+ draggable: false,
7765
+ defaultParams: getDefaultParams(options),
7766
+ columns: columns,
7767
+ syncLocation: false,
7768
+ keepItemSelectionOnPageChange: true,
7769
+ checkOnItemClick: false,
7770
+ labelTpl: `\${${options.labelFieldName}}`,
7771
+ autoFillHeight: false, // 自动高度效果不理想,先关闭
7772
+ columnsTogglable: false,
7773
+ }
7774
+ }
7702
7775
 
7703
7776
 
7704
- let body = null;
7705
- const id = `listview_${objectSchema.name}`;
7706
- if(options.formFactor === 'SMALL' && false){
7707
- delete bodyProps.bulkActions;
7708
- delete bodyProps.headerToolbar;
7709
- delete bodyProps.footerToolbar;
7710
- const card = await getCardSchema(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: objectSchema.NAME_FIELD_KEY || 'name'}, options, {actions: false}));
7711
- body = Object.assign({}, card , {
7712
- type: 'crud',
7713
- primaryField: '_id',
7714
- id: id,
7715
- name: id,
7716
- keepItemSelectionOnPageChange: false,
7717
- api: await getTableApi(objectSchema, fields, options),
7718
- hiddenOn: options.tableHiddenOn,
7719
- },
7720
- bodyProps
7721
- );
7722
- }else {
7723
- let labelFieldName = objectSchema.NAME_FIELD_KEY || 'name';
7724
- // organizations 对象的历史遗留问题, fullname 被标记为了 名称字段. 在此处特殊处理.
7725
- if(objectSchema.name === 'organizations'){
7726
- labelFieldName = 'name';
7727
- }
7728
- const table = await getTableSchema$1(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: labelFieldName}, options));
7729
- delete table.mode;
7730
7777
 
7731
- body = Object.assign({}, table, {
7732
- type: 'crud',
7733
- primaryField: '_id',
7734
- affixHeader: false,
7735
- id: id,
7736
- name: id,
7737
- keepItemSelectionOnPageChange: true,
7738
- api: await getTableApi(objectSchema, fields, options),
7739
- hiddenOn: options.tableHiddenOn,
7740
- autoFillHeight: options.isRelated ? false : true,
7741
- className: `flex-auto ${crudClassName || ""}`,
7742
- bodyClassName: "bg-white",
7743
- crudClassName: crudClassName,
7744
- },
7745
- bodyProps,
7746
- );
7778
+ /**
7779
+ *
7780
+ * @param {*} mainObject
7781
+ * @param {*} fields
7782
+ * @param {*} options = {filter: listview 过滤条件, ...}
7783
+ * @returns
7784
+ */
7785
+ async function getTableApi(mainObject, fields, options){
7786
+ const searchableFields = [];
7787
+ let { filter, filtersFunction, sort, top, setDataToComponentId = '' } = options;
7788
+
7789
+ if(___default.isArray(filter)){
7790
+ filter = ___default.map(filter, function(item){
7791
+ if(item.operation){
7792
+ return [item.field, item.operation, item.value];
7793
+ }else {
7794
+ return item
7795
+ }
7796
+ });
7747
7797
  }
7798
+ if(!filter){
7799
+ filter = [];
7800
+ }
7801
+ let baseFilters = null;
7802
+ if(filter){
7803
+ baseFilters = filter;
7804
+ }
7805
+ ___default.each(fields,function(field){
7806
+ if(field.searchable){
7807
+ searchableFields.push(field.name);
7808
+ }
7809
+ });
7748
7810
 
7749
- const defaults = options.defaults;
7750
- if (defaults) {
7751
- const listSchema = defaults.listSchema || {};
7752
- body = defaultsDeep({}, listSchema, body);
7753
- const headerSchema = defaults.headerSchema;
7754
- const footerSchema = defaults.footerSchema;
7755
- if (headerSchema || footerSchema) {
7756
- let wrappedBody = [body];
7757
- if (headerSchema) {
7758
- if(___default__default.isArray(headerSchema)){
7759
- wrappedBody = ___default__default.union(headerSchema,wrappedBody);
7760
- }
7761
- else {
7762
- wrappedBody.unshift(headerSchema);
7763
- }
7811
+ const fileFields = {};
7812
+ const fileFieldsKeys = [];
7813
+ // 含有optionsFunction属性, 无reference_to属性的lookup字段
7814
+ const lookupFields = {};
7815
+ fields.forEach((item)=>{
7816
+ if(___default.includes(['image','avatar','file'], item.type)){
7817
+ fileFieldsKeys.push(item.name);
7818
+ fileFields[item.name] = {
7819
+ name: item.name,
7820
+ type: item.type,
7821
+ multiple: item.multiple
7822
+ };
7764
7823
  }
7765
- if (footerSchema) {
7766
- if(___default__default.isArray(footerSchema)){
7767
- wrappedBody = ___default__default.union(wrappedBody,footerSchema);
7768
- }
7769
- else {
7770
- wrappedBody.push(footerSchema);
7771
- }
7824
+ if(___default.includes(['lookup'], item.type) && !item.reference_to ){
7825
+ lookupFields[item.name] = item;
7772
7826
  }
7773
- body = wrappedBody;
7774
- }
7827
+ });
7828
+
7829
+ let valueField = mainObject.key_field || '_id';
7830
+ const api = await getApi(mainObject, null, fields, {count: options.queryCount, alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"`});
7831
+
7832
+ if(options.isRelated){
7833
+ api.url += "&recordId=${_master.recordId}";
7775
7834
  }
7776
- // console.timeEnd('getObjectCRUD');
7777
- // TODO: data应该只留loaded,其他属性都改为从上层传递下来
7778
- return {
7779
- type: 'service',
7780
- className: '',
7781
- id: `service_${id}`,
7782
- name: `page`,
7783
- data: {
7784
- objectName: objectSchema.name,
7785
- // _id: null,
7786
- recordPermissions: objectSchema.permissions,
7787
- uiSchema: objectSchema,
7788
- // loaded: false //crud接收适配器中设置为true,否则就是刷新浏览器第一次加载
7789
- },
7790
- body: body
7791
- }
7792
- }
7793
7835
 
7794
- const getGlobalData = (mode)=>{
7795
- const user = getSteedosAuth();
7796
- return {mode: mode, user: user, spaceId: user.spaceId, userId: user.userId}
7797
- };
7836
+ api.data.$term = "$term";
7837
+ api.data.term = "$term";
7838
+ api.data.$self = "$$";
7839
+ api.data.self = "$$";
7840
+ api.data.filter = "$filter";
7841
+ api.data.loaded = "${loaded}";
7842
+ api.data.listViewId = "${listViewId}";
7843
+ api.data.listName = "${listName}";
7844
+ api.requestAdaptor = `
7845
+ // selfData 中的数据由 CRUD 控制. selfData中,只能获取到 CRUD 给定的data. 无法从数据链中获取数据.
7846
+ let selfData = JSON.parse(JSON.stringify(api.data.$self));
7847
+ // 保留一份初始data,以供自定义发送适配器中获取原始数据。
7848
+ const data = _.cloneDeep(api.data);
7849
+ try{
7850
+ // TODO: 不应该直接在这里取localStorage,应该从外面传入
7851
+ const listViewId = api.data.listViewId;
7852
+ const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
7853
+ let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
7854
+ if(localListViewProps){
7855
+ localListViewProps = JSON.parse(localListViewProps);
7856
+ selfData = Object.assign({}, localListViewProps, selfData);
7857
+ if(!api.data.filter){
7858
+ api.data.filter = localListViewProps.filter;
7859
+ }
7860
+ if(!api.data.loaded){
7861
+ // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
7862
+ // 所以会把localSearchableFilter中已经存过的页码覆盖
7863
+ // 如果是第一次加载组件始终让翻页页码从本地存储中取值
7864
+ let formFactor = "${options.formFactor}";
7865
+ // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
7866
+ api.data.pageNo = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
7867
+ }
7868
+ }
7869
+ }
7870
+ catch(ex){
7871
+ console.error("本地存储中crud参数解析异常:", ex);
7872
+ }
7873
+ ${baseFilters ? `var systemFilters = ${JSON.stringify(baseFilters)};` : 'var systemFilters = [];'}
7874
+ var _ids = []
7875
+ const filtersFunction = ${filtersFunction};
7876
+ if(filtersFunction){
7877
+ const _filters = filtersFunction(systemFilters, api.data.$self);
7878
+ if(api.data.listName == "recent"){
7879
+ _ids = _filters[2]
7880
+ }
7881
+ if(_filters && _filters.length > 0){
7882
+ if(_.isEmpty(systemFilters)){
7883
+ systemFilters = _filters || [];
7884
+ }else{
7885
+ systemFilters = [systemFilters, 'and', _filters];
7886
+ }
7887
+ }
7888
+ }
7889
+ let userFilters =[];
7890
+
7891
+ if(_.isEmpty(systemFilters)){
7892
+ systemFilters = api.data.filter || [];
7893
+ }else{
7894
+ if(!_.isEmpty(api.data.filter)){
7895
+ systemFilters = [systemFilters, 'and', api.data.filter];
7896
+ }
7897
+ }
7898
+ var pageSize = api.data.pageSize || 10;
7899
+ var pageNo = api.data.pageNo || 1;
7900
+ var skip = (pageNo - 1) * pageSize;
7901
+ var orderBy = api.data.orderBy || '';
7902
+ var orderDir = api.data.orderDir || '';
7903
+ var sort = orderBy + ' ' + orderDir;
7904
+ sort = orderBy ? sort : "${sort || ''}";
7905
+ var allowSearchFields = ${JSON.stringify(searchableFields)};
7906
+ if(api.data.$term){
7907
+ userFilters = [["name", "contains", "'+ api.data.$term +'"]];
7908
+ }else if(selfData.op === 'loadOptions' && selfData.value){
7909
+ userFilters = [["${valueField.name}", "=", selfData.value]];
7910
+ }
7911
+
7912
+ var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
7798
7913
 
7799
- const getFormFields = (objectSchema, formProps)=>{
7800
- /**
7801
- * fieldsExtend: 重写字段定义
7802
- * fields: 包含的字段
7803
- * excludedFields: 排除的字段
7804
- */
7805
- const { fieldsExtend, fields: includedFields, excludedFields } = formProps;
7806
-
7807
- let fields = {};
7808
- // 以uiSchema fields 为基础, 遍历字段, 并更新字段定义
7809
- ___default__default.forEach(objectSchema.fields, (field, fieldName)=>{
7810
- if(!lodash.has(field, "name")){
7811
- field.name = fieldName;
7812
- }
7813
- if(fieldsExtend && fieldsExtend[fieldName]){
7814
- fields[field.name] = Object.assign({}, field, fieldsExtend[fieldName], {name: field.name});
7815
- }else {
7816
- fields[field.name] = field;
7817
- }
7818
- });
7914
+ if(searchableFilter.length > 0){
7915
+ if(userFilters.length > 0 ){
7916
+ userFilters = [userFilters, 'and', searchableFilter];
7917
+ }else{
7918
+ userFilters = searchableFilter;
7919
+ }
7920
+ }
7819
7921
 
7820
- if(!___default__default.isEmpty(includedFields) && ___default__default.isArray(includedFields)){
7821
- const includedFieldsMap = {};
7822
- ___default__default.each(includedFields, (fName, index)=>{
7823
- if(fields[fName]){
7824
- includedFieldsMap[fName] = Object.assign({}, fields[fName], {sort_no: index});
7825
- }
7826
- });
7827
- fields = includedFieldsMap;
7828
- }
7922
+ if(allowSearchFields){
7923
+ allowSearchFields.forEach(function(key){
7924
+ const keyValue = selfData[key];
7925
+ if(_.isString(keyValue)){
7926
+ userFilters.push([key, "contains", keyValue]);
7927
+ }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
7928
+ userFilters.push([key, "=", keyValue]);
7929
+ }
7930
+ })
7931
+ }
7829
7932
 
7830
- if(!___default__default.isEmpty(excludedFields) && ___default__default.isArray(excludedFields)){
7831
- ___default__default.each(excludedFields, (fName)=>{
7832
- delete fields[fName];
7833
- });
7834
- }
7933
+ if(selfData.__keywords && allowSearchFields){
7934
+ const keywordsFilters = [];
7935
+ allowSearchFields.forEach(function(key, index){
7936
+ const keyValue = selfData.__keywords;
7937
+ if(keyValue){
7938
+ keywordsFilters.push([key, "contains", keyValue]);
7939
+ if(index < allowSearchFields.length - 1){
7940
+ keywordsFilters.push('or');
7941
+ }
7942
+ }
7943
+ })
7944
+ userFilters.push(keywordsFilters);
7945
+ };
7835
7946
 
7836
- return lodash.sortBy(___default__default.values(fields), "sort_no");
7837
- };
7947
+ let filters = [];
7838
7948
 
7839
- async function getObjectForm(objectSchema, ctx){
7840
- const { recordId, formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, tabId, appId, defaults } = ctx;
7841
- const fields = ___default__default.values(objectSchema.fields);
7842
- const formFields = getFormFields(objectSchema, ctx);
7843
- const formSchema = defaults && defaults.formSchema || {};
7844
- if(___default__default.has(formSchema, 'className')){
7845
- formSchema.className = 'steedos-amis-form';
7846
- }
7847
- const amisSchema = {
7848
- type: 'service',
7849
- className: 'p-0',
7850
- name: `page_edit_${recordId}`,
7851
- api: await getEditFormInitApi(objectSchema, recordId, fields, ctx),
7852
- data:{
7853
- editFormInited: false
7854
- },
7855
- // data: {global: getGlobalData('edit'), recordId: recordId, objectName: objectSchema.name, context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
7856
- initApi: null,
7857
- initFetch: null ,
7858
- body: [defaultsDeep({}, formSchema, {
7859
- type: "form",
7860
- mode: layout,
7861
- data: {
7862
- "&": "${initialValues}"
7863
- },
7864
- labelAlign,
7865
- persistData: false,
7866
- resetAfterSubmit: true,
7867
- preventEnterSubmit: true,
7868
- promptPageLeave: true,
7869
- canAccessSuperData: false,
7870
- name: `form_edit_${recordId}`,
7871
- debug: false,
7872
- title: "",
7873
- submitText: "", // amis 表单不显示提交按钮, 表单提交由项目代码接管
7874
- api: await getSaveApi(objectSchema, recordId, fields, ctx),
7875
- initFetch: recordId != 'new',
7876
- body: await getFormBody(fields, formFields, ctx),
7877
- panelClassName:'m-0 sm:rounded-lg shadow-none border-none',
7878
- bodyClassName: 'p-0',
7879
- className: 'steedos-amis-form',
7880
- hiddenOn: "${editFormInited != true}",
7881
- onEvent: {
7882
- "submitSucc": {
7883
- "weight": 0,
7884
- "actions": [
7885
- {
7886
- "actionType": "broadcast",
7887
- "args": {
7888
- "eventName": `@data.changed.${objectSchema.name}`
7889
- },
7890
- "data": {
7891
- "objectName": `${objectSchema.name}`,
7892
- "displayAs": "${displayAs}"
7893
- }
7894
- },
7895
- {
7896
- "actionType": "broadcast",
7897
- "args": {
7898
- "eventName": "@data.changed.${_master.objectName}"
7899
- },
7900
- "data": {
7901
- "objectName": "${_master.objectName}",
7902
- "_isRelated": "${_isRelated || _master._isRelated}"
7903
- },
7904
- "expression": `\${_master.objectName != '${objectSchema.name}' && _master.objectName}`
7905
- },
7906
- // {
7907
- // "actionType": "custom",
7908
- // "script": "debugger;"
7909
- // },
7910
- // {
7911
- // "args": {},
7912
- // "actionType": "closeDialog"
7913
- // }
7914
- ]
7915
- }
7949
+ if(!_.isEmpty(systemFilters)){
7950
+ filters = systemFilters;
7951
+ };
7952
+ if(api.data.$self.additionalFilters){
7953
+ if(_.isString(api.data.$self.additionalFilters)){
7954
+ userFilters.push(eval(api.data.$self.additionalFilters))
7955
+ }else{
7956
+ userFilters.push(api.data.$self.additionalFilters)
7957
+ }
7916
7958
  }
7917
- })]
7918
- };
7919
- if(formSchema.id){
7920
- amisSchema.id = `service-${formSchema.id}`;
7921
- }
7922
- return amisSchema;
7923
- }
7924
7959
 
7925
- async function getObjectDetail(objectSchema, recordId, ctx){
7926
- const { formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, formInitProps } = ctx;
7927
- const fields = ___default__default.values(objectSchema.fields);
7928
- const formFields = getFormFields(objectSchema, ctx);
7929
- const serviceId = `service_detail_page`;
7930
- return {
7931
- type: 'service',
7932
- name: `page_readonly_${recordId}`,
7933
- id: serviceId,
7934
- data: {global: getGlobalData('read'), context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
7935
- api: await getReadonlyFormInitApi(objectSchema, recordId, fields, formInitProps),
7936
- body: [
7937
- {
7938
- "type": "wrapper", //form 的 hiddenOn 会导致 form onEvent 异常, 使用wrapper包裹一次form,并在wrapper上控制显隐
7939
- hiddenOn: "${recordLoaded != true}",
7940
- "className": "p-0 m-0",
7941
- "body": {
7942
- type: "form",
7943
- mode: layout,
7944
- labelAlign,
7945
- persistData: false,
7946
- promptPageLeave: false,
7947
- name: `form_readonly_${recordId}`,
7948
- debug: false,
7949
- title: "",
7950
- data: {
7951
- "formData": "$$"
7952
- },
7953
- wrapWithPanel: false,
7954
- body: await getFormBody(map(fields, (field)=>{field.readonly = true; return field;}), map(formFields, (field)=>{field.readonly = true; return field;}), Object.assign({}, ctx, {showSystemFields: true})),
7955
- className: 'steedos-amis-form bg-white',
7956
- actions: [], // 不显示表单默认的提交按钮
7957
- onEvent: {
7958
- [`@data.changed.${objectSchema.name}`]: { // 由于amis service 组件的 onEvent 存在bug ,此处借助form来刷新 上层 service https://github.com/baidu/amis/issues/6294
7959
- "actions": [
7960
- {
7961
- "actionType": "reload",
7962
- "componentId": serviceId,
7963
- "expression": "this.__deletedRecord != true"
7964
- },
7965
- {
7966
- // "args": {
7967
- // "url": "/app/${appId}/${objectName}/grid/${side_listview_id}",
7968
- // "blank": false
7969
- // },
7970
- "actionType": "custom",
7971
- "script": "Steedos.goBack()",
7972
- "expression": "this.__deletedRecord === true"
7973
- }
7974
- ]
7960
+ if(api.data.$self._isRelated){
7961
+ const self = api.data.$self;
7962
+ const relatedKey = self.relatedKey;
7963
+ const refField = self.uiSchema.fields[relatedKey];
7964
+ const masterRecord = self._master.record;
7965
+ const masterObjectName = self._master.objectName;
7966
+ let relatedValue = self._master.recordId;
7967
+ if(refField.reference_to_field && refField.reference_to_field != '_id'){
7968
+ relatedValue = masterRecord[refField.reference_to_field]
7969
+ }
7970
+ let relatedFilters;
7971
+ if (
7972
+ refField._reference_to ||
7973
+ (refField.reference_to && !_.isString(refField.reference_to))
7974
+ ) {
7975
+ relatedFilters = [
7976
+ [relatedKey + "/o", "=", masterObjectName],
7977
+ [relatedKey + "/ids", "=", relatedValue],
7978
+ ];
7979
+ } else {
7980
+ relatedFilters = [relatedKey, "=", relatedValue];
7981
+ }
7982
+ userFilters.push(relatedFilters)
7983
+ }
7984
+
7985
+ if(!_.isEmpty(userFilters)){
7986
+ if(_.isEmpty(filters)){
7987
+ filters = userFilters;
7988
+ }else{
7989
+ filters = [filters, 'and', userFilters]
7990
+ }
7991
+ }
7992
+ api.data._ids = _ids;
7993
+ api.data = {
7994
+ query: api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim())
7995
+ }
7996
+ ${options.requestAdaptor || ''}
7997
+ return api;
7998
+ `;
7999
+ api.adaptor = `
8000
+ if(api.body.listName == "recent"){
8001
+ payload.data.rows = _.sortBy(payload.data.rows, function(item){
8002
+ return _.indexOf(api.body._ids, item._id)
8003
+ });
8004
+ }
8005
+ const enable_tree = ${mainObject.enable_tree};
8006
+ if(!enable_tree){
8007
+ _.each(payload.data.rows, function(item, index){
8008
+ const {pageNo, pageSize} = api.body;
8009
+ const skip = (pageNo - 1) * pageSize;
8010
+ item._index = skip + index + 1;
8011
+ })
8012
+ }
8013
+ window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8014
+ let fileFields = ${JSON.stringify(fileFields)};
8015
+ let lookupFields = ${JSON.stringify(lookupFields)};
8016
+ _.each(payload.data.rows, function(item, index){
8017
+ _.each(fileFields , (field, key)=>{
8018
+ if(item[key] && item._display && item._display[key]){
8019
+ let value = item._display[key];
8020
+ if(!_.isArray(value)){
8021
+ value = [value]
8022
+ };
8023
+ if(field.type === 'file'){
8024
+ item[key] = value
8025
+ }else{
8026
+ item[key] = _.map(value, 'url')
7975
8027
  }
7976
- }
7977
- },
7978
- }
7979
- ],
7980
- onEvent: {
7981
- "fetchInited": {
7982
- "weight": 0,
7983
- "actions": [
7984
- {
7985
- actionType: 'broadcast',
7986
- eventName: "recordLoaded",
7987
- args: {
7988
- eventName: "recordLoaded"
7989
- },
7990
- data: {
7991
- objectName: "${event.data.__objectName}",
7992
- record: "${event.data.__record}"
7993
- },
7994
- expression: "${event.data.__response.error != true}"
7995
- },
7996
- {
7997
- "actionType": "setValue",
7998
- "args": {
7999
- value: {
8000
- "recordLoaded": true,
8001
- }
8002
- },
8003
- expression: "${event.data.__response.error != true}"
8004
8028
  }
8005
- ]
8006
- }
8029
+ })
8030
+ _.each(lookupFields , (field, key)=>{
8031
+ if(item[key]){
8032
+ if(field._optionsFunction){
8033
+ const optionsFunction = eval("(" + field._optionsFunction+ ")")(item);
8034
+ item[key + '__label'] = _.map(_.filter(optionsFunction, function(option){return _.includes(item[key], option.value)}), 'label').join(' ');
8035
+ }
8036
+ }
8037
+ })
8038
+ })
8039
+
8040
+ if(enable_tree){
8041
+ const records = payload.data.rows || [];
8042
+ const getTreeOptions = SteedosUI.getTreeOptions
8043
+ payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
8044
+ }
8045
+
8046
+
8047
+ try{
8048
+ // TODO: 不应该直接在这里取localStorage,应该从外面传入
8049
+ const listViewId = api.body.listViewId;
8050
+ const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
8051
+ /**
8052
+ * localListViewProps规范来自crud请求api中api.data.$self参数值的。
8053
+ * 比如:{"perPage":20,"page":1,"__searchable__name":"7","__searchable__between__n1__c":[null,null],"filter":[["name","contains","a"]]}
8054
+ * __searchable__...:顶部放大镜搜索条件
8055
+ * filter:右侧过滤器
8056
+ * perPage:每页条数
8057
+ * page:当前页码
8058
+ * orderBy:排序字段
8059
+ * orderDir:排序方向
8060
+ */
8061
+ let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
8062
+ let selfData = JSON.parse(JSON.stringify(api.body.$self));
8063
+ if(localListViewProps){
8064
+ localListViewProps = JSON.parse(localListViewProps);
8065
+ selfData = Object.assign({}, localListViewProps, selfData, { filter: api.body.filter });
8066
+ if(!api.body.loaded){
8067
+ // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
8068
+ // 所以会把localSearchableFilter中已经存过的页码覆盖
8069
+ // 如果是第一次加载组件始终让翻页页码从本地存储中取值
8070
+ let formFactor = "${options.formFactor}";
8071
+ // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
8072
+ selfData.page = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
8073
+ }
8007
8074
  }
8075
+ delete selfData.context;
8076
+ delete selfData.global;
8077
+ sessionStorage.setItem(listViewPropsStoreKey, JSON.stringify(selfData));
8078
+ // 返回页码到UI界面
8079
+ payload.data.page= selfData.page;
8008
8080
  }
8081
+ catch(ex){
8082
+ console.error("本地存储中crud参数解析异常:", ex);
8083
+ }
8084
+ // 标记加载过,后续优先从本地存储中加载相关参数
8085
+ payload.data.loaded= true;
8086
+
8087
+ const setDataToComponentId = "${setDataToComponentId}";
8088
+ if(setDataToComponentId){
8089
+ SteedosUI.getRef(api.body.$self.$scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8090
+ };
8091
+ ${options.adaptor || ''}
8092
+ return payload;
8093
+ `;
8094
+ return api;
8009
8095
  }
8010
8096
 
8011
- /*
8012
- * @Author: baozhoutao@steedos.com
8013
- * @Date: 2022-08-04 10:42:49
8014
- * @LastEditors: baozhoutao@steedos.com
8015
- * @LastEditTime: 2022-08-25 10:28:47
8016
- * @Description:
8017
- */
8018
- var config = {
8019
- listView: {
8020
- newRecordMode: 'modal',
8021
- editRecordMode: 'modal',
8022
- perPage: 20
8097
+ async function getApi(object, recordId, fields, options){
8098
+ const data = await getFindQuery(object, recordId, fields, options);
8099
+ return {
8100
+ method: "post",
8101
+ url: getApi$2(), // + "&recordId=${recordId}"
8102
+ data: data,
8103
+ headers: {
8104
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8105
+ }
8023
8106
  }
8024
- };
8107
+ }
8025
8108
 
8026
- async function getTableColumns$1(fields, options){
8027
- const columns = [{name: '_index',type: 'text', width: 32, placeholder: ""}];
8028
- for (const field of fields) {
8029
- if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
8030
- const previewFileScript = `
8031
- var data = event.data;
8032
- var file_name = data.versions ? data.name : "${field.label}";
8033
- var file_id = data._id;
8034
- SteedosUI.previewFile && SteedosUI.previewFile({file_name, file_id});
8035
- `;
8036
- columns.push({
8037
- "type": "button",
8038
- "label": `<%=data.versions ? data.name : "${field.label}"%>`,
8039
- "className": "whitespace-nowrap",
8040
- "level": "link",
8041
- "onEvent": {
8042
- "click": {
8043
- "actions": [
8044
- {
8045
- "args": {
8046
- "api": {
8047
- "url": "${context.rootUrl}/api/files/files/${versions[0]}?download=true",
8048
- "method": "get",
8049
- "headers": {
8050
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
8051
- }
8052
- }
8053
- },
8054
- "actionType": "download",
8055
- "expression": "!!!window?.nw?.require"//浏览器上直接下载
8056
- },
8057
- {
8058
- "args": {},
8059
- "actionType": "custom",
8060
- "script": previewFileScript,
8061
- "expression": "!!window?.nw?.require" //PC客户端预览附件
8062
- }
8063
- ]
8064
- }
8065
- }
8066
- });
8067
- }else if(field.type === 'toggle'){
8068
- columns.push(Object.assign({}, {
8069
- type: "switch",
8070
- name: field.name,
8071
- label: field.label,
8072
- width: field.width,
8073
- toggled: field.toggled,
8074
- disabled: true,
8075
- className:"whitespace-nowrap",
8076
- }, field.amis, {name: field.name}));
8077
- }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
8078
- columns.push(Object.assign({}, {
8079
- type: "switch",
8080
- name: field.name,
8081
- label: field.label,
8082
- width: field.width,
8083
- toggled: field.toggled,
8084
- disabled: true,
8085
- className:"whitespace-nowrap",
8086
- ...getAmisFileReadonlySchema(field)
8087
- }, field.amis, {name: field.name}));
8088
- }
8089
- else if(field.type === 'select'){
8090
- const map = getSelectMap(field.options);
8091
- columns.push(Object.assign({}, {
8092
- type: "mapping",
8093
- name: field.name,
8094
- label: field.label,
8095
- map: map,
8096
- sortable: field.sortable,
8097
- width: field.width,
8098
- toggled: field.toggled,
8099
- className:"whitespace-nowrap",
8100
- }, field.amis, {name: field.name}));
8109
+ function getRecordPermissionsApi(object, recordId, options){
8110
+ const data = getRecordPermissionsQuery(object, recordId, options);
8111
+ return {
8112
+ method: "post",
8113
+ url: getApi$2(),
8114
+ data: data,
8115
+ headers: {
8116
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8101
8117
  }
8102
- else {
8103
- const tpl = await getFieldTpl(field, options);
8118
+ }
8119
+ }
8104
8120
 
8105
- let type = 'text';
8106
- if(tpl){
8107
- type = 'tpl';
8108
- }else if(field.type === 'html'){
8109
- type = 'markdown';
8110
- }else if(field.type === 'url' && field.show_as_qr){
8111
- type = 'qr-code';
8112
- }
8113
- let className = "";
8114
- if(field.type === 'textarea'){
8115
- className = 'min-w-56';
8116
- }
8117
- if(field.wrap === false){
8118
- className += " whitespace-nowrap";
8121
+ const API_CACHE = 100;
8122
+
8123
+ function getReadonlyFormAdaptor(object, fields){
8124
+ let scriptStr = '';
8125
+ const selectFields = ___default.filter(fields, function(field){return field.name.indexOf('.') < 0 && ((field.type == 'select' && field.options) || ((field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to))});
8126
+ const gridAndObjectFieldsName = ___default.map(___default.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type === 'object' || field.type === 'grid')}), 'name');
8127
+ ___default.each(selectFields, function(field){
8128
+ if(!___default.includes(OMIT_FIELDS, field.name)){
8129
+ field.name;
8130
+ if(field.options){
8131
+ const options = JSON.stringify({options: field.options});
8132
+ scriptStr = scriptStr + `var ${field.name}Options= (${options}).options;`;
8133
+ }else if(field.optionsFunction){
8134
+ scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`;
8135
+ }else if(field._optionsFunction){
8136
+ scriptStr = scriptStr + `var ${field.name}Options = eval(${field._optionsFunction})(api.data);`;
8119
8137
  }
8120
- if(!field.hidden && !field.extra){
8121
- columns.push(Object.assign({}, {
8122
- name: field.name,
8123
- label: field.label,
8124
- sortable: field.sortable,
8125
- // searchable: field.searchable,
8126
- width: field.width,
8127
- type: type,
8128
- tpl: tpl,
8129
- toggled: field.toggled,
8130
- className,
8131
- options: field.type === 'html' ? {html: true} : null
8132
- // toggled: true
8133
- }, field.amis, {name: field.name}));
8138
+ if(field.multiple){
8139
+ scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`;
8140
+ }else {
8141
+ scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`;
8142
+ scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`;
8134
8143
  }
8135
8144
  }
8136
-
8145
+ });
8146
+
8147
+ // const refFields = _.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to});
8148
+ // _.each(refFields, function(field){
8149
+ // if(!_.includes(OMIT_FIELDS, field.name)){
8150
+ // const valueField = field.reference_to_field || '_id';
8151
+ // scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`
8152
+ // if(field.multiple){
8153
+ // scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`
8154
+ // }else{
8155
+ // scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`
8156
+ // scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`
8157
+ // }
8158
+ // }
8159
+ // })
8160
+
8161
+ return `
8162
+ if(payload.data.data.length === 0){
8163
+ return {
8164
+ status: 2,
8165
+ msg: "无法找到记录"
8166
+ }
8137
8167
  }
8138
- // columns.push(getOperation(fields));
8139
- if(!___default.some(columns, { name: options.labelFieldName })){
8140
- const href = Router$1.getObjectDetailPath({
8141
- ...options, formFactor: options.formFactor, appId: "${appId}", objectName: options.objectName || "${objectName}", recordId: `\${${options.idFieldName}}`
8142
- });
8143
- columns[0].type = "tpl";
8144
- columns[0].tpl = `<a href="${href}">\${${columns[0].name}}</a>`;
8168
+ if(payload.data.data){
8169
+ var data = payload.data.data[0];
8170
+ var gridAndObjectFieldsName = ${JSON.stringify(gridAndObjectFieldsName)};
8171
+ try{
8172
+ ${scriptStr}
8173
+ ${getScriptForAddUrlPrefixForImgFields(fields)}
8174
+ ${getScriptForRewriteValueForFileFields(fields)}
8175
+ }catch(e){
8176
+ console.error(e)
8177
+ }
8178
+ // 原始记录
8179
+ var record = _.cloneDeep(data);
8180
+ try{
8181
+ _.each(gridAndObjectFieldsName, function(name){
8182
+ data[name] = data._display[name];
8183
+ })
8184
+ }catch(e){
8185
+ console.error(e)
8186
+ }
8187
+ payload.data = data;
8188
+ payload.data.__objectName = "${object.name}";
8189
+ payload.data.__record = record;
8190
+ window.postMessage(Object.assign({type: "record.loaded"}, {record: record}), "*")
8145
8191
  }
8146
- return columns;
8192
+ if(payload.errors){
8193
+ payload.status = 2;
8194
+ payload.msg = payload.errors[0].message;
8195
+ }
8196
+ return payload;
8197
+ `
8147
8198
  }
8148
8199
 
8149
- /**
8150
- * 生成移动端列表每行显示的amis行
8151
- * @param {*} tpls 要显示的每个字段的tpl
8152
- * @returns {
8153
- "type": "wrapper",
8154
- "body": [{
8155
- "type": "tpl",
8156
- "tpl": tpls[index].tpl,
8157
- "className": "truncate"//左侧样式类
8158
- },{
8159
- "type": "tpl",
8160
- "tpl": tpls[index + 1].tpl,
8161
- "className": "truncate ml-2 flex flex-shrink-0"//右侧样式类
8162
- }],
8163
- "size": "none",
8164
- "className": "flex items-center justify-between"//每行样式类
8200
+ async function getReadonlyFormInitApi(object, recordId, fields, options){
8201
+ return {
8202
+ method: "post",
8203
+ url: getApi$2()+"&recordId=${recordId}",
8204
+ cache: API_CACHE,
8205
+ // requestAdaptor: "console.log('getReadonlyFormInitApi requestAdaptor', api);return api;",
8206
+ adaptor: getReadonlyFormAdaptor(object, fields),
8207
+ data: await getFindOneQuery$1(object, recordId, fields, options),
8208
+ headers: {
8209
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8210
+ }
8165
8211
  }
8166
- */
8167
- function getMobileLines(tpls){
8168
- let lines = [];
8169
- let maxLineCount = 2;
8170
- let lineChildren = [];
8171
- let isNewLine = false;
8172
- let isLeft = true;
8173
- let lineChildrenClassName = "";
8174
- let lineClassName = "flex items-center justify-between h-[20px]";
8175
- tpls.forEach(function(item){
8176
- if(isNewLine && lines.length < maxLineCount){
8177
- lines.push({
8178
- "type": "wrapper",
8179
- "body": lineChildren,
8180
- "size": "none",
8181
- "className": lineClassName
8182
- });
8183
- lineChildren = [];
8212
+ }
8213
+
8214
+ /*
8215
+ img/avatar字段值添加URL前缀使其在amis中正常显示图片。
8216
+ */
8217
+ function getScriptForAddUrlPrefixForImgFields(fields){
8218
+ let imgFieldsKeys = [];
8219
+ let imgFields = {};
8220
+ fields.forEach((item)=>{
8221
+ if(___default.includes(['image','avatar'], item.type)){
8222
+ imgFieldsKeys.push(item.name);
8223
+ imgFields[item.name] = {
8224
+ name: item.name,
8225
+ type: item.type,
8226
+ multiple: item.multiple
8227
+ };
8184
8228
  }
8185
- if(isLeft){
8186
- // 左侧半行
8187
- lineChildrenClassName = "steedos-listview-item-left truncate";
8188
- if(item.field.is_wide){
8189
- // 左侧全行样式可以单独写
8190
- lineChildrenClassName = "steedos-listview-item-wide truncate";
8229
+ });
8230
+ if(!imgFieldsKeys.length){
8231
+ return '';
8232
+ }
8233
+ return `
8234
+ // image字段值添加URL前缀
8235
+ let imgFieldsKeys = ${JSON.stringify(imgFieldsKeys)};
8236
+ let imgFields = ${JSON.stringify(imgFields)};
8237
+ imgFieldsKeys.forEach((item)=>{
8238
+ let imgFieldValue = data[item];
8239
+ let imgFieldDisplayValue = data._display && data._display[item];
8240
+ if(imgFieldValue && imgFieldValue.length){
8241
+ let fieldProps = imgFields[item];
8242
+ if(fieldProps.multiple){
8243
+ if(imgFieldDisplayValue instanceof Array){
8244
+ data[item] = imgFieldDisplayValue.map((i)=>{ return i.url });
8245
+ }
8246
+ }else{
8247
+ data[item] = imgFieldDisplayValue && imgFieldDisplayValue.url;
8248
+ }
8249
+ }
8250
+ })
8251
+ `
8252
+ }
8253
+
8254
+ /*
8255
+ file字段值重写使其在amis中正常显示附件名、点击附件名下载文件。
8256
+ */
8257
+ function getScriptForRewriteValueForFileFields(fields){
8258
+ let fileFieldsKeys = [];
8259
+ let fileFields = {};
8260
+ fields.forEach((item)=>{
8261
+ if(item.type === 'file'){
8262
+ fileFieldsKeys.push(item.name);
8263
+ fileFields[item.name] = {
8264
+ name: item.name,
8265
+ multiple: item.multiple
8266
+ };
8267
+ }
8268
+ });
8269
+ if(!fileFieldsKeys.length){
8270
+ return '';
8271
+ }
8272
+ return `
8273
+ // file字段值重写以便编辑时正常显示附件名、点击附件名正常下载附件
8274
+ let fileFieldsKeys = ${JSON.stringify(fileFieldsKeys)};
8275
+ let fileFields = ${JSON.stringify(fileFields)};
8276
+ fileFieldsKeys.forEach((item)=>{
8277
+ let fileFieldValue = data[item];
8278
+ let fileFieldDisplayValue = data._display && data._display[item];
8279
+ if(fileFieldValue && fileFieldValue.length){
8280
+ if(fileFields[item].multiple){
8281
+ if(fileFieldDisplayValue instanceof Array){
8282
+ data[item] = fileFieldDisplayValue.map((item, index)=>{
8283
+ return {
8284
+ value: fileFieldValue[index],
8285
+ name: item.name,
8286
+ url: item.url + "?download=true",
8287
+ state: "uploaded"
8288
+ }
8289
+ });
8290
+ }
8291
+ }else{
8292
+ data[item] = [{
8293
+ value: fileFieldValue,
8294
+ name: fileFieldDisplayValue.name,
8295
+ url: fileFieldDisplayValue.url + "?download=true",
8296
+ state: "uploaded"
8297
+ }];
8298
+ }
8299
+ }
8300
+ })
8301
+ `
8302
+ }
8303
+
8304
+ async function getEditFormInitApi(object, recordId, fields, options){
8305
+ const data = await getFindOneQuery$1(object, recordId, fields);
8306
+ data.recordId = "${recordId}";
8307
+ data.objectName = "${objectName}";
8308
+ data.uiSchema = "${uiSchema}";
8309
+ data.global = "${global}";
8310
+ data.context = "${context}";
8311
+ data.defaultData = "${defaultData}";
8312
+ data._master = "${_master}";
8313
+
8314
+ return {
8315
+ method: "post",
8316
+ url: getApi$2() + '&objectName=${objectName}' ,
8317
+ // sendOn: "!!this.recordId",
8318
+ cache: API_CACHE,
8319
+ requestAdaptor: `
8320
+ // 所有不想在network请求中发送的数据都应该从data中分离出来,data变量只需要留下query才需要发送出去
8321
+ var { recordId, objectName, uiSchema, global, context, ...data} = api.data;
8322
+ if(!recordId){
8323
+ // 新建则不请求任何数据
8324
+ data.query = "{data:" + objectName + "(filters: " + JSON.stringify(["_id", "=", null]) + ", top: 1){_id}}";
8325
+ }
8326
+ api.data = data;
8327
+ ${options.initApiRequestAdaptor || ''}
8328
+ return api;
8329
+ `,
8330
+ adaptor: `
8331
+ const recordId = api.body.recordId;
8332
+ let initialValues={};
8333
+ if(recordId && payload.data.data){
8334
+ var data = payload.data.data[0];
8335
+ const dataKeys = _.keys(data);
8336
+ const uiSchema = api.body.uiSchema;
8337
+ const fieldKeys = uiSchema && _.keys(uiSchema.fields);
8338
+
8339
+ if(data){
8340
+ ${getScriptForAddUrlPrefixForImgFields(fields)}
8341
+ ${getScriptForRewriteValueForFileFields(fields)}
8342
+
8343
+ _.each(dataKeys, function(key){
8344
+ if(fieldKeys.indexOf(key)<0){
8345
+ delete data[key];
8346
+ }
8347
+ })
8348
+
8349
+ //初始化接口返回的字段移除字段值为null的字段
8350
+ for (key in data){
8351
+ if(data[key] === null){
8352
+ delete data[key];
8353
+ }
8354
+ }
8355
+ };
8356
+ initialValues = data;
8357
+ }
8358
+ else{
8359
+ var uiSchema = api.body.uiSchema;
8360
+ var defaultData = api.body.defaultData;
8361
+ var defaultValues = {};
8362
+ _.each(uiSchema?.fields, function(field){
8363
+ var value = SteedosUI.getFieldDefaultValue(field, api.body.global);
8364
+ if(value){
8365
+ defaultValues[field.name] = value;
8366
+ }
8367
+ });
8368
+ if(defaultData && _.isObject(defaultData) && !_.isArray(defaultData)){
8369
+ defaultValues = Object.assign({}, defaultValues, defaultData)
8370
+ }
8371
+ if(uiSchema.form){
8372
+ try{
8373
+ var objectFormConfig = JSON.parse(uiSchema.form);
8374
+ var formInitialValuesFun = objectFormConfig.initialValues;
8375
+ if(formInitialValuesFun){
8376
+ formInitialValuesFun = new Function("return " + formInitialValuesFun)();
8377
+ }
8378
+ if(typeof formInitialValuesFun === "function"){
8379
+ initialValues = formInitialValuesFun.apply({doc: defaultValues || {} , global: api.body.global, master: api.body._master })
8380
+ }
8381
+ }
8382
+ catch(ex){
8383
+ console.warn(ex);
8384
+ }
8385
+ }
8386
+ if(_.isObject(initialValues)){
8387
+ // uiSchema.form.initialValues为函数且执行后为json,则优先取initialValues中的默认值
8388
+ initialValues = Object.assign({}, defaultValues, initialValues);
8389
+ }
8390
+ else{
8391
+ initialValues = defaultValues;
8392
+ }
8191
8393
  }
8192
- if(lines.length === 0){
8193
- // 第一个字段加粗黑色显示
8194
- lineChildrenClassName += " font-bold text-gray-800";
8394
+ // data下的变量需要在保存接口(getSaveApi)中被删除。
8395
+ payload.data = {
8396
+ ...initialValues
8195
8397
  }
8398
+ ${options.initApiAdaptor || ''}
8399
+ return payload;
8400
+ `,
8401
+ responseData: {
8402
+ initialValues: "$$",
8403
+ editFormInited: true
8404
+ },
8405
+ data: data,
8406
+ headers: {
8407
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8196
8408
  }
8197
- else {
8198
- // 右侧半行
8199
- lineChildrenClassName = "steedos-listview-item-right truncate ml-2 flex flex-shrink-0";
8200
- }
8201
- lineChildren.push({
8202
- "type": "tpl",
8203
- "tpl": item.tpl,
8204
- "className": lineChildrenClassName
8205
- });
8206
-
8207
- if(item.field.is_wide){
8208
- // 宽字段占整行
8209
- isLeft = true;
8210
- isNewLine = true;
8211
- }
8212
- else {
8213
- isLeft = !isLeft;
8214
- isNewLine = isLeft;
8215
- }
8216
- });
8217
-
8218
- if(lineChildren.length && lines.length < maxLineCount){
8219
- lines.push({
8220
- "type": "wrapper",
8221
- "body": lineChildren,
8222
- "size": "none",
8223
- "className": lineClassName
8224
- });
8225
8409
  }
8226
-
8227
- return lines;
8228
8410
  }
8229
8411
 
8230
- async function getMobileTableColumns(fields, options){
8231
- const columns = [];
8232
- let nameField = {};
8233
- let tpls = [];
8234
- for (const field of fields) {
8235
- let tpl = "";
8236
- if(field.is_name || field.name === options.labelFieldName){
8237
- nameField = field;
8238
- options.onlyDisplayLabel = true;
8239
- tpl = await getFieldTpl(field, options);
8240
- }
8241
- else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
8242
- // 图片和附件类型字段暂时显示为附件名称,后续需要再优化
8243
- tpl = `\${_display.${field.name}.name}`;
8244
- }
8245
- else {
8246
- if(field.type === 'lookup' || field.type === 'master_detail'){
8247
- options.onlyDisplayLabel = true;
8412
+
8413
+ function getSaveApi(object, recordId, fields, options){
8414
+ return {
8415
+ method: 'post',
8416
+ url: getApi$2(),
8417
+ data: getSaveQuery(object, recordId),
8418
+ requestAdaptor: getSaveRequestAdaptor(fields, options),
8419
+ responseData: {
8420
+ "recordId": "${record._id}"
8421
+ },
8422
+ adaptor: `
8423
+ if(payload.errors){
8424
+ payload.status = 2;
8425
+ payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
8248
8426
  }
8249
- tpl = await getFieldTpl(field, options);
8250
- }
8251
- if(!tpl){
8252
- tpl = `\${${field.name}}`;
8427
+ ${options.apiAdaptor || ''}
8428
+ return payload;
8429
+ `,
8430
+ headers: {
8431
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8253
8432
  }
8254
- if(!field.hidden && !field.extra){
8255
- tpls.push({ field, tpl });
8433
+ }
8434
+ }
8435
+
8436
+ function getBatchDelete(objectName){
8437
+ return {
8438
+ method: 'post',
8439
+ url: getApi$2(),
8440
+ requestAdaptor: `
8441
+ var ids = api.data.ids.split(",");
8442
+ var deleteArray = [];
8443
+ ids.forEach((id,index)=>{
8444
+ deleteArray.push(\`delete__\${index}:${objectName}__delete(id: "\${id}")\`);
8445
+ })
8446
+ api.data = {query: \`mutation{\${deleteArray.join(',')}}\`};
8447
+ return api;
8448
+ `,
8449
+ data: {
8450
+ ids: `\${ids}`
8451
+ },
8452
+ headers: {
8453
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8256
8454
  }
8257
8455
  }
8258
- const url = getNameTplUrl(nameField, options);
8456
+ }
8259
8457
 
8260
- const columnLines = getMobileLines(tpls);
8458
+ const DEFAULT_CALENDAR_OPTIONS = {
8459
+ startDateExpr: "start",
8460
+ endDateExpr: "end",
8461
+ allDayExpr: "is_all_day",
8462
+ textExpr: "name"
8463
+ };
8261
8464
 
8465
+ async function getCalendarApi(mainObject, fields, options) {
8466
+ if (!options) {
8467
+ options = {};
8468
+ }
8469
+ const calendarOptions = options.calendarOptions;
8470
+ const searchableFields = [];
8471
+ let { filter, sort, top, setDataToComponentId = '' } = options;
8262
8472
 
8263
- let column = {
8264
- name: nameField.name,
8265
- label: nameField.label,
8266
- sortable: nameField.sortable,
8267
- type: "button",
8268
- level: "link",
8269
- actionType: "link",
8270
- link: url,
8271
- innerClassName: "steedos-listview-item block text-gray-500",
8272
- body: {
8273
- "type": "wrapper",
8274
- "body": columnLines,
8275
- "size": "none",
8276
- "className": "p-1"
8277
- }
8278
- };
8279
-
8280
- if(options.objectName === 'cms_files'){
8281
- if(window.Meteor?.isCordova){
8282
- column = {
8283
- ...column,
8284
- actionType: "",
8285
- link: "",
8286
- onEvent: {
8287
- "click": {
8288
- "actions": [
8289
- {
8290
- "script": `
8291
- let cms_url = "/api/files/files/"+event.data.versions[0]+"?download=true"
8292
- Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
8293
- `,
8294
- "actionType": "custom"
8295
- }
8296
- ],
8297
- "weight": 0
8298
- }
8299
- }
8300
- };
8301
- }else {
8302
- column = {
8303
- ...column,
8304
- actionType: "",
8305
- link: "",
8306
- onEvent: {
8307
- "click": {
8308
- "actions": [
8309
- {
8310
- "args": {
8311
- "api": {
8312
- "url": url,
8313
- "method": "get",
8314
- "headers": {
8315
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
8316
- }
8317
- }
8318
- },
8319
- "actionType": "download"
8320
- }
8321
- ],
8322
- "weight": 0
8323
- }
8324
- }
8325
- };
8326
- }
8327
-
8328
- }
8473
+ if (!top) {
8474
+ // 日历请求不翻页
8475
+ top = 200;
8476
+ }
8329
8477
 
8330
- columns.push(column);
8331
-
8478
+ if (___default__default.isArray(filter)) {
8479
+ filter = ___default__default.map(filter, function (item) {
8480
+ if (item.operation) {
8481
+ return [item.field, item.operation, item.value];
8482
+ } else {
8483
+ return item
8484
+ }
8485
+ });
8486
+ }
8487
+ if (!filter) {
8488
+ filter = [];
8489
+ }
8332
8490
 
8333
- return columns;
8334
- }
8491
+ ___default__default.each(fields, function (field) {
8492
+ if (field.searchable) {
8493
+ searchableFields.push(field.name);
8494
+ }
8495
+ });
8335
8496
 
8336
- function getDefaultParams(options){
8337
- return {
8338
- perPage: options.top || options.perPage || config.listView.perPage
8497
+ const idFieldName = mainObject.idFieldName || "_id";
8498
+ let valueField = mainObject.key_field || '_id';
8499
+ const api = await getApi(mainObject, null, fields, { alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"` });
8500
+ api.data.$term = "$term";
8501
+ api.data.$self = "$$";
8502
+ api.data.filter = "$filter";
8503
+ api.data.pageSize = top || 10;
8504
+ api.requestAdaptor = `
8505
+ let selfData = JSON.parse(JSON.stringify(api.data.$self));
8506
+ var filters = api.data.filter || ${JSON.stringify(filter)} || [];
8507
+ const eventFetchInfo = selfData.fetchInfo;
8508
+ const startDateExpr = "${calendarOptions.startDateExpr}";
8509
+ const endDateExpr = "${calendarOptions.endDateExpr}";
8510
+ const eventDurationFilters = [[endDateExpr, ">=", eventFetchInfo.start], [startDateExpr, "<=", eventFetchInfo.end]];
8511
+ if(_.isEmpty(filters)){
8512
+ filters = eventDurationFilters;
8513
+ }else{
8514
+ filters = [filters, 'and', eventDurationFilters]
8339
8515
  }
8340
- }
8341
-
8342
- function getButtonVisibleOn(button){
8343
- let visible= button.visible;
8344
8516
 
8345
- if(button._visible){
8346
- visible = button._visible;
8517
+ if(api.data.$self.additionalFilters){
8518
+ filters.push(api.data.$self.additionalFilters)
8347
8519
  }
8348
8520
 
8349
- if(isBoolean(visible)){
8350
- visible = visible.toString();
8521
+ var pageSize = api.data.pageSize || 10;
8522
+ var pageNo = api.data.pageNo || 1;
8523
+ var skip = (pageNo - 1) * pageSize;
8524
+ var orderBy = api.data.orderBy || '';
8525
+ var orderDir = api.data.orderDir || '';
8526
+ var sort = orderBy + ' ' + orderDir;
8527
+ sort = orderBy ? sort : "${sort}";
8528
+ var allowSearchFields = ${JSON.stringify(searchableFields)};
8529
+ if(api.data.$term){
8530
+ filters = [["name", "contains", "'+ api.data.$term +'"]];
8531
+ }else if(selfData.op === 'loadOptions' && selfData.value){
8532
+ filters = [["${valueField.name}", "=", selfData.value]];
8351
8533
  }
8534
+ var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
8352
8535
 
8353
- if(visible){
8354
- // if(visible.indexOf("Meteor.") > 0 || visible.indexOf("Creator.") > 0 || visible.indexOf("Session.") > 0){
8355
- // console.warn('无效的visible', visible)
8356
- // return 'false';
8357
- // }
8358
- if(visible.trim().startsWith('function')){
8359
- return `${visible}(objectName, typeof _id === 'undefined' ? null: _id, typeof record === 'undefined' ? (typeof recordPermissions === 'undefined' ? {} : recordPermissions) : record.recordPermissions, data)`
8536
+ if(searchableFilter.length > 0){
8537
+ if(filters.length > 0 ){
8538
+ filters = [filters, 'and', searchableFilter];
8539
+ }else{
8540
+ filters = searchableFilter;
8360
8541
  }
8361
- return visible;
8362
8542
  }
8363
8543
 
8364
- if(button.type === 'amis_button'){
8365
- const amisSchema = button.amis_schema;
8366
- if(amisSchema && amisSchema.body && amisSchema.body.length > 0){
8367
- const btn1 = amisSchema.body[0];
8368
- return btn1.visibleOn
8369
- }
8544
+ if(allowSearchFields){
8545
+ allowSearchFields.forEach(function(key){
8546
+ const keyValue = selfData[key];
8547
+ if(_.isString(keyValue)){
8548
+ filters.push([key, "contains", keyValue]);
8549
+ }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8550
+ filters.push([key, "=", keyValue]);
8551
+ }
8552
+ })
8370
8553
  }
8371
- }
8372
-
8373
- async function getTableOperation(ctx){
8374
- const buttons = ctx.buttons;
8375
- const operationButtons = [];
8376
- each(buttons, (button)=>{
8377
- if(isBoolean(button.visible)){
8378
- button.visible = button.visible.toString();
8379
- }
8380
- // operationButtons.push({
8381
- // type: 'button',
8382
- // label: button.label,
8383
- // visibleOn: button.visible ? `${button.visible}` : (button._visible ? `${button._visible}` : null),
8384
- // onEvent: {
8385
- // click: {
8386
- // actions: []
8387
- // }
8388
- // }
8389
- // })
8390
8554
 
8391
- operationButtons.push({
8392
- type: 'steedos-object-button',
8393
- name: button.name,
8394
- objectName: button.objectName,
8395
- visibleOn: getButtonVisibleOn(button),
8396
- className: 'antd-Button--default'
8397
- });
8398
- });
8399
- if(operationButtons.length < 1){
8400
- return ;
8401
- }
8402
- return {
8403
- type: 'operation',
8404
- label: '操作',
8405
- fixed: 'right',
8406
- labelClassName: 'text-center',
8407
- className: 'text-center steedos-listview-operation w-20',
8408
- buttons: [
8409
- {
8410
- "type": "steedos-dropdown-button",
8411
- "label": "xxx",
8412
- "buttons": operationButtons,
8413
- "placement": "bottomRight",
8414
- "overlayClassName": "shadow !min-w-[160px]",
8415
- "trigger": ["click"],
8416
- "id": "u:c2140a365019",
8417
- onOpenApi: {
8418
- url: `\${context.rootUrl}/service/api/@\${objectName}/recordPermissions/\${_id}`,
8419
- method: "get",
8420
- data: {
8421
- $: "$$",
8422
- objectName: "${objectName}",
8423
- listViewId: "${listViewId}",
8424
- appId: "${appId}",
8425
- formFactor: "${formFactor}",
8426
- context: `\${context}`
8427
- },
8428
- headers: {
8429
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8430
- },
8431
- adaptor: `
8432
- payload = {
8433
- record: {
8434
- recordPermissions: payload
8435
- }
8436
- };
8437
- return payload;
8438
- `,
8555
+ if(selfData.__keywords && allowSearchFields){
8556
+ const keywordsFilters = [];
8557
+ allowSearchFields.forEach(function(key, index){
8558
+ const keyValue = selfData.__keywords;
8559
+ if(keyValue){
8560
+ keywordsFilters.push([key, "contains", keyValue]);
8561
+ if(index < allowSearchFields.length - 1){
8562
+ keywordsFilters.push('or');
8439
8563
  }
8440
- }
8441
- ]
8564
+ }
8565
+ })
8566
+ filters.push(keywordsFilters);
8567
+ }
8568
+ api.data.query = api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim());
8569
+ delete api.data.$term;
8570
+ delete api.data.filter;
8571
+ delete api.data.pageSize;
8572
+ delete api.data.pageNo;
8573
+ delete api.data.orderBy;
8574
+ delete api.data.orderDir;
8575
+ return api;
8576
+ `;
8577
+ api.adaptor = `
8578
+ window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8579
+ const setDataToComponentId = "${setDataToComponentId}";
8580
+ if(setDataToComponentId){
8581
+ SteedosUI.getRef(api.body.$self.scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8442
8582
  }
8583
+ const rows = payload.data.rows || [];
8584
+ const selfData = api.data.$self;
8585
+ const events = rows.map(function(n){
8586
+ return {
8587
+ id: n["${idFieldName}"],
8588
+ title: n["${calendarOptions.textExpr}"],
8589
+ start: n["${calendarOptions.startDateExpr}"],
8590
+ end: n["${calendarOptions.endDateExpr}"],
8591
+ allDay: n["${calendarOptions.allDayExpr}"],
8592
+ extendedProps: n
8593
+ }
8594
+ });
8595
+ const successCallback = selfData.successCallback;
8596
+ const failureCallback = selfData.failureCallback;
8597
+ successCallback(events);
8598
+ return payload;
8599
+ `;
8600
+ return api;
8443
8601
  }
8444
8602
 
8445
- async function getTableSchema$1(fields, options){
8446
- if(!options){
8447
- options = {};
8448
- }
8449
- let columns = [];
8450
- if(options.formFactor === 'SMALL' || ["split"].indexOf(options.displayAs) > -1){
8451
- columns = await getMobileTableColumns(fields, options);
8452
- }
8453
- else {
8454
- columns = await getTableColumns$1(fields, options);
8455
- columns.push(await getTableOperation(options));
8603
+ function getCalendarRecordPermissionsApi(mainObject, recordId) {
8604
+ const api = getRecordPermissionsApi(mainObject, recordId, { alias: 'rows', limit: 1, fields: ["allowEdit"] });
8605
+ api.data.$self = "$$";
8606
+ api.adaptor = `
8607
+ const rows = payload.data.rows || [];
8608
+ const selfData = api.data.$self;
8609
+ const revert = selfData.revert;
8610
+ const recordPermissions = rows[0] && rows[0].recordPermissions;
8611
+ const editable = !!(recordPermissions && recordPermissions.allowEdit);
8612
+ if(!editable){
8613
+ // 没有权限时还原
8614
+ revert && revert();
8456
8615
  }
8457
- return {
8458
- mode: "table",
8459
- name: "thelist",
8460
- headerToolbarClassName: "py-2 px-2 border-gray-300 bg-gray-100 border-solid border-b",
8461
- className: "",
8462
- draggable: false,
8463
- defaultParams: getDefaultParams(options),
8464
- columns: columns,
8465
- syncLocation: false,
8466
- keepItemSelectionOnPageChange: true,
8467
- checkOnItemClick: false,
8468
- labelTpl: `\${${options.labelFieldName}}`,
8469
- autoFillHeight: false, // 自动高度效果不理想,先关闭
8470
- columnsTogglable: false,
8616
+ payload.data.editable = editable;
8617
+ return payload;
8618
+ `;
8619
+ return api;
8620
+ }
8621
+
8622
+ function getCalendarRecordSaveApi(object, calendarOptions) {
8623
+ const formData = {};
8624
+ const idFieldName = object.idFieldName || "_id";
8625
+ formData[idFieldName] = "${event.data.event.id}";
8626
+ const nameFieldKey = object.NAME_FIELD_KEY || "name";
8627
+ formData[nameFieldKey] = "${event.data.event.title}";
8628
+ formData[calendarOptions.startDateExpr] = "${event.data.event.start}";
8629
+ formData[calendarOptions.endDateExpr] = "${event.data.event.end}";
8630
+ formData[calendarOptions.allDayExpr] = "${event.data.event.allDay}";
8631
+ // formData[calendarOptions.textExpr] = "${event.data.event.title}";
8632
+ const apiData = {
8633
+ objectName: "${objectName}",
8634
+ $: formData,
8635
+ $self: "$$"
8636
+ };
8637
+ const saveDataTpl = `
8638
+ const formData = api.data.$;
8639
+ const objectName = api.data.objectName;
8640
+ let query = \`mutation{record: \${objectName}__update(id: "\${formData.${idFieldName}}", doc: {__saveData}){${idFieldName}}}\`;
8641
+ delete formData.${idFieldName};
8642
+ let __saveData = JSON.stringify(JSON.stringify(formData));
8643
+ `;
8644
+ const requestAdaptor = `
8645
+ ${saveDataTpl}
8646
+ api.data.query = query.replace('{__saveData}', __saveData);
8647
+ return api;
8648
+ `;
8649
+
8650
+ return {
8651
+ method: 'post',
8652
+ url: getApi$2(),
8653
+ data: apiData,
8654
+ requestAdaptor: requestAdaptor,
8655
+ adaptor: `
8656
+ if(payload.errors){
8657
+ payload.status = 2;
8658
+ payload.msg = payload.errors[0].message;
8659
+ const revert = api.data.$self.event.data.revert;
8660
+ revert && revert();
8661
+ }
8662
+ return payload;
8663
+ `,
8664
+ headers: {
8665
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8471
8666
  }
8667
+ };
8472
8668
  }
8473
8669
 
8474
-
8475
-
8476
8670
  /**
8477
- *
8478
- * @param {*} mainObject
8479
- * @param {*} fields
8480
- * @param {*} options = {filter: listview 过滤条件, ...}
8481
- * @returns
8671
+ * 列表视图Calendar amisSchema
8672
+ * @param {*} objectSchema 对象UISchema
8673
+ * @returns amisSchema
8482
8674
  */
8483
- async function getTableApi(mainObject, fields, options){
8484
- const searchableFields = [];
8485
- let { filter, filtersFunction, sort, top, setDataToComponentId = '' } = options;
8675
+ async function getObjectCalendar(objectSchema, calendarOptions, options) {
8676
+ const permissions = objectSchema.permissions;
8677
+ if (!options) {
8678
+ options = {};
8679
+ }
8486
8680
 
8487
- if(___default.isArray(filter)){
8488
- filter = ___default.map(filter, function(item){
8489
- if(item.operation){
8490
- return [item.field, item.operation, item.value];
8491
- }else {
8492
- return item
8493
- }
8494
- });
8681
+ calendarOptions = Object.assign({}, DEFAULT_CALENDAR_OPTIONS, omitBy(calendarOptions, isNil));
8682
+
8683
+ const titleFields = calendarOptions.title || [
8684
+ calendarOptions.startDateExpr,
8685
+ calendarOptions.endDateExpr,
8686
+ calendarOptions.allDayExpr,
8687
+ calendarOptions.textExpr
8688
+ ];
8689
+ let fields = [];
8690
+ each(titleFields, function (n) {
8691
+ if (objectSchema.fields[n]) {
8692
+ fields.push(objectSchema.fields[n]);
8495
8693
  }
8496
- if(!filter){
8497
- filter = [];
8694
+ });
8695
+
8696
+ if (objectSchema.fields[calendarOptions.allDayExpr]) {
8697
+ fields.push(objectSchema.fields[calendarOptions.allDayExpr]);
8698
+ }
8699
+
8700
+ let sort = options.sort;
8701
+ if (!sort) {
8702
+ const sortField = options.sortField;
8703
+ const sortOrder = options.sortOrder;
8704
+ if (sortField) {
8705
+ let sortStr = sortField + ' ' + sortOrder || 'asc';
8706
+ sort = sortStr;
8498
8707
  }
8499
- let baseFilters = null;
8500
- if(filter){
8501
- baseFilters = filter;
8708
+ }
8709
+ let initialView = calendarOptions.currentView;
8710
+ if (initialView) {
8711
+ // day, week, month, agenda
8712
+ switch (initialView) {
8713
+ case "day":
8714
+ initialView = "timeGridDay";
8715
+ break;
8716
+ case "week":
8717
+ initialView = "timeGridWeek";
8718
+ break;
8719
+ case "month":
8720
+ initialView = "dayGridMonth";
8721
+ break;
8722
+ case "agenda":
8723
+ initialView = "listWeek";
8724
+ break;
8502
8725
  }
8503
- ___default.each(fields,function(field){
8504
- if(field.searchable){
8505
- searchableFields.push(field.name);
8506
- }
8507
- });
8508
-
8509
- const fileFields = {};
8510
- const fileFieldsKeys = [];
8511
- // 含有optionsFunction属性, 无reference_to属性的lookup字段
8512
- const lookupFields = {};
8513
- fields.forEach((item)=>{
8514
- if(___default.includes(['image','avatar','file'], item.type)){
8515
- fileFieldsKeys.push(item.name);
8516
- fileFields[item.name] = {
8517
- name: item.name,
8518
- type: item.type,
8519
- multiple: item.multiple
8520
- };
8521
- }
8522
- if(___default.includes(['lookup'], item.type) && !item.reference_to ){
8523
- lookupFields[item.name] = item;
8524
- }
8525
- });
8726
+ }
8727
+ else {
8728
+ initialView = "timeGridWeek";
8729
+ }
8526
8730
 
8527
- let valueField = mainObject.key_field || '_id';
8528
- const api = await getApi(mainObject, null, fields, {count: options.queryCount, alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"`});
8731
+ options.calendarOptions = calendarOptions;
8732
+ const api = await getCalendarApi(objectSchema, fields, options);
8529
8733
 
8530
- if(options.isRelated){
8531
- api.url += "&recordId=${_master.recordId}";
8532
- }
8734
+ const onGetEventsScript = `
8735
+ const api = ${JSON.stringify(api)};
8736
+ event.data.calendarOptions = ${JSON.stringify(calendarOptions)};
8737
+ doAction({
8738
+ "actionType": 'ajax',
8739
+ "args": {
8740
+ "api": api
8741
+ },
8742
+ });
8743
+ `;
8533
8744
 
8534
- api.data.$term = "$term";
8535
- api.data.term = "$term";
8536
- api.data.$self = "$$";
8537
- api.data.self = "$$";
8538
- api.data.filter = "$filter";
8539
- api.data.loaded = "${loaded}";
8540
- api.data.listViewId = "${listViewId}";
8541
- api.data.listName = "${listName}";
8542
- api.requestAdaptor = `
8543
- // selfData 中的数据由 CRUD 控制. selfData中,只能获取到 CRUD 给定的data. 无法从数据链中获取数据.
8544
- let selfData = JSON.parse(JSON.stringify(api.data.$self));
8545
- // 保留一份初始data,以供自定义发送适配器中获取原始数据。
8546
- const data = _.cloneDeep(api.data);
8547
- try{
8548
- // TODO: 不应该直接在这里取localStorage,应该从外面传入
8549
- const listViewId = api.data.listViewId;
8550
- const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
8551
- let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
8552
- if(localListViewProps){
8553
- localListViewProps = JSON.parse(localListViewProps);
8554
- selfData = Object.assign({}, localListViewProps, selfData);
8555
- if(!api.data.filter){
8556
- api.data.filter = localListViewProps.filter;
8557
- }
8558
- if(!api.data.loaded){
8559
- // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
8560
- // 所以会把localSearchableFilter中已经存过的页码覆盖
8561
- // 如果是第一次加载组件始终让翻页页码从本地存储中取值
8562
- let formFactor = "${options.formFactor}";
8563
- // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
8564
- api.data.pageNo = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
8565
- }
8566
- }
8567
- }
8568
- catch(ex){
8569
- console.error("本地存储中crud参数解析异常:", ex);
8570
- }
8571
- ${baseFilters ? `var systemFilters = ${JSON.stringify(baseFilters)};` : 'var systemFilters = [];'}
8572
- var _ids = []
8573
- const filtersFunction = ${filtersFunction};
8574
- if(filtersFunction){
8575
- const _filters = filtersFunction(systemFilters, api.data.$self);
8576
- if(api.data.listName == "recent"){
8577
- _ids = _filters[2]
8578
- }
8579
- if(_filters && _filters.length > 0){
8580
- if(_.isEmpty(systemFilters)){
8581
- systemFilters = _filters || [];
8582
- }else{
8583
- systemFilters = [systemFilters, 'and', _filters];
8745
+ const onSelectScript = `
8746
+ const data = event.data;
8747
+ const doc = {};
8748
+ doc["${calendarOptions.startDateExpr}"] = data.start;
8749
+ doc["${calendarOptions.endDateExpr}"] = data.end;
8750
+ doc["${calendarOptions.allDayExpr}"] = data.allDay;
8751
+ doc["${calendarOptions.textExpr}"] = data.title;
8752
+ // ObjectForm会认作用域下的变量值
8753
+ // TODO: 待组件支持initValues属性后应该改掉,不应该通过data直接传值
8754
+ // TODO: 全天事件属性传入doc了但是没有生效,需要手动在ObjectForm中勾选全天事件
8755
+ const title = "新建 ${objectSchema.label}";
8756
+ doAction(
8757
+ {
8758
+ "actionType": "dialog",
8759
+ "dialog": {
8760
+ "type": "dialog",
8761
+ "title": title,
8762
+ "body": [
8763
+ {
8764
+ "type": "steedos-object-form",
8765
+ "objectApiName": "\${objectName}",
8766
+ "mode": "edit",
8767
+ "defaultData": doc,
8768
+ "onEvent": {
8769
+ "submitSucc": {
8770
+ "weight": 0,
8771
+ "actions": [
8772
+ {
8773
+ "actionType": "custom",
8774
+ "script": "event.data.view?.calendar.refetchEvents();"
8775
+ }
8776
+ ]
8584
8777
  }
8778
+ }
8585
8779
  }
8780
+ ],
8781
+ "closeOnEsc": false,
8782
+ "closeOnOutside": false,
8783
+ "showCloseButton": true,
8784
+ "size": "lg"
8586
8785
  }
8587
- let userFilters =[];
8588
-
8589
- if(_.isEmpty(systemFilters)){
8590
- systemFilters = api.data.filter || [];
8591
- }else{
8592
- if(!_.isEmpty(api.data.filter)){
8593
- systemFilters = [systemFilters, 'and', api.data.filter];
8594
- }
8595
- }
8596
- var pageSize = api.data.pageSize || 10;
8597
- var pageNo = api.data.pageNo || 1;
8598
- var skip = (pageNo - 1) * pageSize;
8599
- var orderBy = api.data.orderBy || '';
8600
- var orderDir = api.data.orderDir || '';
8601
- var sort = orderBy + ' ' + orderDir;
8602
- sort = orderBy ? sort : "${sort || ''}";
8603
- var allowSearchFields = ${JSON.stringify(searchableFields)};
8604
- if(api.data.$term){
8605
- userFilters = [["name", "contains", "'+ api.data.$term +'"]];
8606
- }else if(selfData.op === 'loadOptions' && selfData.value){
8607
- userFilters = [["${valueField.name}", "=", selfData.value]];
8608
- }
8609
-
8610
- var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
8611
-
8612
- if(searchableFilter.length > 0){
8613
- if(userFilters.length > 0 ){
8614
- userFilters = [userFilters, 'and', searchableFilter];
8615
- }else{
8616
- userFilters = searchableFilter;
8617
- }
8618
- }
8786
+ });
8787
+ `;
8619
8788
 
8620
- if(allowSearchFields){
8621
- allowSearchFields.forEach(function(key){
8622
- const keyValue = selfData[key];
8623
- if(_.isString(keyValue)){
8624
- userFilters.push([key, "contains", keyValue]);
8625
- }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8626
- userFilters.push([key, "=", keyValue]);
8627
- }
8628
- })
8629
- }
8789
+ const onEventClickScript = `
8790
+ const data = event.data;
8791
+ const eventData = data.event;
8792
+ const appId = data.appId;
8793
+ const objectName = data.objectName;
8794
+ const eventId = data.event && data.event.id;
8795
+ doAction({
8796
+ "actionType": "dialog",
8797
+ "dialog": {
8798
+ "type": "dialog",
8799
+ "title": "",
8800
+ "body": [
8801
+ {
8802
+ "type": "steedos-record-detail",
8803
+ "objectApiName": "\${objectName}",
8804
+ "recordId": data.event && data.event.id
8805
+ }
8806
+ ],
8807
+ "closeOnEsc": false,
8808
+ "closeOnOutside": false,
8809
+ "showCloseButton": true,
8810
+ "size": "lg",
8811
+ "actions": []
8812
+ }
8813
+ });
8814
+ `;
8630
8815
 
8631
- if(selfData.__keywords && allowSearchFields){
8632
- const keywordsFilters = [];
8633
- allowSearchFields.forEach(function(key, index){
8634
- const keyValue = selfData.__keywords;
8635
- if(keyValue){
8636
- keywordsFilters.push([key, "contains", keyValue]);
8637
- if(index < allowSearchFields.length - 1){
8638
- keywordsFilters.push('or');
8639
- }
8640
- }
8641
- })
8642
- userFilters.push(keywordsFilters);
8643
- };
8816
+ const recordId = "${event.id}";
8817
+ const recordPermissionsApi = getCalendarRecordPermissionsApi(objectSchema, recordId);
8818
+ const recordSaveApi = getCalendarRecordSaveApi(objectSchema, calendarOptions);
8644
8819
 
8645
- let filters = [];
8820
+ const businessHours = {
8821
+ daysOfWeek: [1, 2, 3, 4, 5],
8822
+ startTime: '08:00',
8823
+ endTime: '18:00',
8824
+ };
8825
+ if (!isEmpty(calendarOptions.startDayHour)) {
8826
+ businessHours.startTime = `${calendarOptions.startDayHour}:00`;
8827
+ }
8828
+ if (!isEmpty(calendarOptions.endDayHour)) {
8829
+ businessHours.endTime = `${calendarOptions.endDayHour}:00`;
8830
+ }
8646
8831
 
8647
- if(!_.isEmpty(systemFilters)){
8648
- filters = systemFilters;
8649
- };
8650
- if(api.data.$self.additionalFilters){
8651
- if(_.isString(api.data.$self.additionalFilters)){
8652
- userFilters.push(eval(api.data.$self.additionalFilters))
8653
- }else{
8654
- userFilters.push(api.data.$self.additionalFilters)
8655
- }
8832
+ const onEvent = {
8833
+ "getEvents": {
8834
+ "weight": 0,
8835
+ "actions": [
8836
+ {
8837
+ "componentId": "",
8838
+ "args": {
8839
+ },
8840
+ "actionType": "custom",
8841
+ "script": onGetEventsScript
8656
8842
  }
8657
-
8658
- if(api.data.$self._isRelated){
8659
- const self = api.data.$self;
8660
- const relatedKey = self.relatedKey;
8661
- const refField = self.uiSchema.fields[relatedKey];
8662
- const masterRecord = self._master.record;
8663
- const masterObjectName = self._master.objectName;
8664
- let relatedValue = self._master.recordId;
8665
- if(refField.reference_to_field && refField.reference_to_field != '_id'){
8666
- relatedValue = masterRecord[refField.reference_to_field]
8667
- }
8668
- let relatedFilters;
8669
- if (
8670
- refField._reference_to ||
8671
- (refField.reference_to && !_.isString(refField.reference_to))
8672
- ) {
8673
- relatedFilters = [
8674
- [relatedKey + "/o", "=", masterObjectName],
8675
- [relatedKey + "/ids", "=", relatedValue],
8676
- ];
8677
- } else {
8678
- relatedFilters = [relatedKey, "=", relatedValue];
8679
- }
8680
- userFilters.push(relatedFilters)
8843
+ ]
8844
+ },
8845
+ "select": {
8846
+ "weight": 0,
8847
+ "actions": [
8848
+ {
8849
+ "componentId": "",
8850
+ "args": {
8851
+ },
8852
+ "actionType": "custom",
8853
+ "script": onSelectScript
8681
8854
  }
8682
-
8683
- if(!_.isEmpty(userFilters)){
8684
- if(_.isEmpty(filters)){
8685
- filters = userFilters;
8686
- }else{
8687
- filters = [filters, 'and', userFilters]
8688
- }
8855
+ ]
8856
+ },
8857
+ "eventClick": {
8858
+ "weight": 0,
8859
+ "actions": [
8860
+ {
8861
+ "componentId": "",
8862
+ "args": {
8863
+ },
8864
+ "actionType": "custom",
8865
+ "script": onEventClickScript
8689
8866
  }
8690
- api.data._ids = _ids;
8691
- api.data = {
8692
- query: api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim())
8867
+ ]
8868
+ },
8869
+ "eventAdd": {
8870
+ "weight": 0,
8871
+ "actions": [
8872
+ {
8873
+ "componentId": "",
8874
+ "args": {
8875
+ },
8876
+ "actionType": "custom",
8877
+ "script": "console.log('eventAdd'); console.log(event);"
8693
8878
  }
8694
- ${options.requestAdaptor || ''}
8695
- return api;
8696
- `;
8697
- api.adaptor = `
8698
- if(api.body.listName == "recent"){
8699
- payload.data.rows = _.sortBy(payload.data.rows, function(item){
8700
- return _.indexOf(api.body._ids, item._id)
8701
- });
8702
- }
8703
- const enable_tree = ${mainObject.enable_tree};
8704
- if(!enable_tree){
8705
- _.each(payload.data.rows, function(item, index){
8706
- const {pageNo, pageSize} = api.body;
8707
- const skip = (pageNo - 1) * pageSize;
8708
- item._index = skip + index + 1;
8709
- })
8710
- }
8711
- window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8712
- let fileFields = ${JSON.stringify(fileFields)};
8713
- let lookupFields = ${JSON.stringify(lookupFields)};
8714
- _.each(payload.data.rows, function(item, index){
8715
- _.each(fileFields , (field, key)=>{
8716
- if(item[key] && item._display && item._display[key]){
8717
- let value = item._display[key];
8718
- if(!_.isArray(value)){
8719
- value = [value]
8720
- };
8721
- if(field.type === 'file'){
8722
- item[key] = value
8723
- }else{
8724
- item[key] = _.map(value, 'url')
8725
- }
8726
- }
8727
- })
8728
- _.each(lookupFields , (field, key)=>{
8729
- if(item[key]){
8730
- if(field._optionsFunction){
8731
- const optionsFunction = eval("(" + field._optionsFunction+ ")")(item);
8732
- item[key + '__label'] = _.map(_.filter(optionsFunction, function(option){return _.includes(item[key], option.value)}), 'label').join(' ');
8733
- }
8734
- }
8735
- })
8736
- })
8737
-
8738
- if(enable_tree){
8739
- const records = payload.data.rows || [];
8740
- const getTreeOptions = SteedosUI.getTreeOptions
8741
- payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
8742
- }
8743
-
8744
-
8745
- try{
8746
- // TODO: 不应该直接在这里取localStorage,应该从外面传入
8747
- const listViewId = api.body.listViewId;
8748
- const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
8749
- /**
8750
- * localListViewProps规范来自crud请求api中api.data.$self参数值的。
8751
- * 比如:{"perPage":20,"page":1,"__searchable__name":"7","__searchable__between__n1__c":[null,null],"filter":[["name","contains","a"]]}
8752
- * __searchable__...:顶部放大镜搜索条件
8753
- * filter:右侧过滤器
8754
- * perPage:每页条数
8755
- * page:当前页码
8756
- * orderBy:排序字段
8757
- * orderDir:排序方向
8758
- */
8759
- let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
8760
- let selfData = JSON.parse(JSON.stringify(api.body.$self));
8761
- if(localListViewProps){
8762
- localListViewProps = JSON.parse(localListViewProps);
8763
- selfData = Object.assign({}, localListViewProps, selfData, { filter: api.body.filter });
8764
- if(!api.body.loaded){
8765
- // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
8766
- // 所以会把localSearchableFilter中已经存过的页码覆盖
8767
- // 如果是第一次加载组件始终让翻页页码从本地存储中取值
8768
- let formFactor = "${options.formFactor}";
8769
- // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
8770
- selfData.page = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
8879
+ ]
8880
+ },
8881
+ "eventChange": {
8882
+ "weight": 0,
8883
+ "actions": [
8884
+ {
8885
+ "actionType": 'ajax',
8886
+ "args": {
8887
+ "api": recordPermissionsApi
8888
+ }
8889
+ },
8890
+ {
8891
+ "actionType": "toast",
8892
+ "expression": "!event.data.editable",
8893
+ "args": {
8894
+ "msgType": "error",
8895
+ "msg": "您没有编辑该记录的权限!",
8896
+ "position": "top-center"
8897
+ }
8898
+ },
8899
+ {
8900
+ "actionType": 'ajax',
8901
+ "expression": "event.data.editable",
8902
+ "args": {
8903
+ "api": recordSaveApi,
8904
+ "messages": {
8905
+ "success": objectSchema.label + "修改成功",
8906
+ "failed": objectSchema.label + "修改失败!"
8771
8907
  }
8908
+ }
8909
+ }
8910
+ ]
8911
+ },
8912
+ "eventRemove": {
8913
+ "weight": 0,
8914
+ "actions": [
8915
+ {
8916
+ "componentId": "",
8917
+ "args": {
8918
+ },
8919
+ "actionType": "custom",
8920
+ "script": "console.log('eventRemove'); console.log(event);"
8921
+ }
8922
+ ]
8923
+ },
8924
+ "eventsSet": {
8925
+ "weight": 0,
8926
+ "actions": [
8927
+ {
8928
+ "componentId": "",
8929
+ "args": {
8930
+ },
8931
+ "actionType": "custom",
8932
+ "script": "console.log('eventsSet'); console.log(event);"
8772
8933
  }
8773
- delete selfData.context;
8774
- delete selfData.global;
8775
- sessionStorage.setItem(listViewPropsStoreKey, JSON.stringify(selfData));
8776
- // 返回页码到UI界面
8777
- payload.data.page= selfData.page;
8778
- }
8779
- catch(ex){
8780
- console.error("本地存储中crud参数解析异常:", ex);
8934
+ ]
8781
8935
  }
8782
- // 标记加载过,后续优先从本地存储中加载相关参数
8783
- payload.data.loaded= true;
8936
+ };
8784
8937
 
8785
- const setDataToComponentId = "${setDataToComponentId}";
8786
- if(setDataToComponentId){
8787
- SteedosUI.getRef(api.body.$self.$scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8788
- };
8789
- ${options.adaptor || ''}
8790
- return payload;
8791
- `;
8792
- return api;
8793
- }
8938
+ Object.assign(onEvent, options.onEvent);
8794
8939
 
8795
- async function getApi(object, recordId, fields, options){
8796
- const data = await getFindQuery(object, recordId, fields, options);
8797
- return {
8798
- method: "post",
8799
- url: getApi$2(), // + "&recordId=${recordId}"
8800
- data: data,
8801
- headers: {
8802
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8803
- }
8940
+ const config = options.config || {};
8941
+ if(config.eventContent && typeof config.eventContent === "string"){
8942
+ const hasReturn = /\breturn\b/.test(config.eventContent);
8943
+ if(hasReturn){
8944
+ try {
8945
+ // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8946
+ let fn = new Function("arg", config.eventContent);
8947
+ config.eventContent = fn;
8948
+ } catch (e) {
8949
+ console.warn(e);
8950
+ }
8804
8951
  }
8805
- }
8952
+ }
8806
8953
 
8807
- function getRecordPermissionsApi(object, recordId, options){
8808
- const data = getRecordPermissionsQuery(object, recordId, options);
8809
- return {
8810
- method: "post",
8811
- url: getApi$2(),
8812
- data: data,
8813
- headers: {
8814
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8815
- }
8954
+ if(config.noEventsContent && typeof config.noEventsContent === "string"){
8955
+ const hasReturn = /\breturn\b/.test(config.noEventsContent);
8956
+ if(hasReturn){
8957
+ try {
8958
+ // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8959
+ let fn = new Function("arg", config.noEventsContent);
8960
+ config.noEventsContent = fn;
8961
+ } catch (e) {
8962
+ console.warn(e);
8963
+ }
8816
8964
  }
8965
+ }
8966
+
8967
+ const amisSchema = {
8968
+ "type": "steedos-fullcalendar",
8969
+ "label": "",
8970
+ "name": "fullcalendar",
8971
+ "placeholder":"${additionalFilters}",//用于触发reload
8972
+ "editable": permissions.allowEdit,
8973
+ "selectable": permissions.allowCreate,
8974
+ "selectMirror": permissions.allowCreate,
8975
+ "initialView": initialView,
8976
+ "businessHours": businessHours,
8977
+ ...config,
8978
+ "onEvent": onEvent
8979
+ };
8980
+ return amisSchema;
8817
8981
  }
8818
8982
 
8819
- const DEFAULT_CALENDAR_OPTIONS = {
8820
- startDateExpr: "start",
8821
- endDateExpr: "end",
8822
- allDayExpr: "is_all_day",
8823
- textExpr: "name"
8983
+ /*
8984
+ * @Author: baozhoutao@steedos.com
8985
+ * @Date: 2022-05-26 16:02:08
8986
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
8987
+ * @LastEditTime: 2023-06-04 15:49:23
8988
+ * @Description:
8989
+ */
8990
+
8991
+ const getFieldSchemaArray = (formFields) => {
8992
+ let fieldSchemaArray = [];
8993
+ fieldSchemaArray.length = 0;
8994
+
8995
+ ___default.forEach(formFields, (field) => {
8996
+ if (!field.group || field.group == 'null' || field.group == '-')
8997
+ field.group = '通用';
8998
+ const fieldName = field.name;
8999
+ let isObjectField = /\w+\.\w+/.test(fieldName);
9000
+ if (field.type == 'grid' || field.type == 'object') {
9001
+ // field.group = field.label
9002
+ field.is_wide = true;
9003
+ }
9004
+
9005
+ if (!isObjectField) {
9006
+ if (!field.hidden) {
9007
+ fieldSchemaArray.push(Object.assign({ name: fieldName }, field, { permission: { allowEdit: true } }));
9008
+ }
9009
+ }
9010
+ });
9011
+ return fieldSchemaArray;
8824
9012
  };
8825
9013
 
8826
- async function getCalendarApi(mainObject, fields, options) {
8827
- if (!options) {
8828
- options = {};
9014
+ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectionName, ctx) => {
9015
+ if (!ctx) {
9016
+ ctx = {};
8829
9017
  }
8830
- const calendarOptions = options.calendarOptions;
8831
- const searchableFields = [];
8832
- let { filter, sort, top, setDataToComponentId = '' } = options;
8833
-
8834
- if (!top) {
8835
- // 日历请求不翻页
8836
- top = 200;
9018
+ const sectionFields = ___default.filter(fieldSchemaArray, { 'group': sectionName });
9019
+ if (sectionFields.length == ___default.filter(sectionFields, ['hidden', true]).length) {
9020
+ return;
8837
9021
  }
8838
9022
 
8839
- if (___default__default.isArray(filter)) {
8840
- filter = ___default__default.map(filter, function (item) {
8841
- if (item.operation) {
8842
- return [item.field, item.operation, item.value];
8843
- } else {
8844
- return item
9023
+ const fieldSetBody = [];
9024
+
9025
+ for (const perField of sectionFields) {
9026
+ let field = perField;
9027
+ if (perField.type === 'grid') {
9028
+ field = await getGridFieldSubFields(perField, formFields);
9029
+ // console.log(`perField.type grid ===> field`, field)
9030
+ } else if (perField.type === 'object') {
9031
+ field = await getObjectFieldSubFields(perField, formFields);
9032
+ // console.log(`perField.type object ===> field`, field)
9033
+ }
9034
+ if (field.name.indexOf(".") < 0) {
9035
+ ctx.__formFields = formFields;
9036
+ const amisField = await convertSFieldToAmisField(field, field.readonly, ctx);
9037
+ // console.log(`${field.name} amisField`, field, amisField)
9038
+ if (amisField) {
9039
+ fieldSetBody.push(amisField);
8845
9040
  }
8846
- });
9041
+ }
8847
9042
  }
8848
- if (!filter) {
8849
- filter = [];
9043
+
9044
+ // fieldSet 已支持显隐控制
9045
+ const sectionFieldsVisibleOn = ___default.map(___default.compact(___default.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
9046
+ return visibleOn;
9047
+ });
9048
+
9049
+ let section = {
9050
+ "type": "fieldSet",
9051
+ "title": sectionName,
9052
+ "collapsable": true,
9053
+ "body": fieldSetBody,
9054
+ };
9055
+
9056
+ if (ctx.enableTabs) {
9057
+ section = {
9058
+ "title": sectionName,
9059
+ "body": fieldSetBody,
9060
+ };
8850
9061
  }
8851
9062
 
8852
- ___default__default.each(fields, function (field) {
8853
- if (field.searchable) {
8854
- searchableFields.push(field.name);
9063
+ if (sectionFieldsVisibleOn.length > 0 && fieldSetBody.length === sectionFieldsVisibleOn.length) {
9064
+ section.visibleOn = `${sectionFieldsVisibleOn.join(" || ")}`;
9065
+ }
9066
+ return section
9067
+ };
9068
+
9069
+ const getSections = async (permissionFields, formFields, ctx) => {
9070
+ if (!ctx) {
9071
+ ctx = {};
9072
+ }
9073
+ const fieldSchemaArray = getFieldSchemaArray(formFields);
9074
+ const _sections = ___default.groupBy(fieldSchemaArray, 'group');
9075
+ const sections = [];
9076
+ var sectionVisibleOns = [];
9077
+ for (const key in _sections) {
9078
+ const section = await getSection(formFields, permissionFields, fieldSchemaArray, key, ctx);
9079
+ if (section.body.length > 0) {
9080
+ if (section.visibleOn) {
9081
+ sectionVisibleOns.push(section.visibleOn);
9082
+ }
9083
+ else {
9084
+ sectionVisibleOns.push("true");
9085
+ }
9086
+ sections.push(section);
8855
9087
  }
9088
+ }
9089
+ /*
9090
+ 为了实现只有一个分组时隐藏该分组标题,需要分三种情况(分组如果没有visibleon属性就代表一定显示,有visibleon需要进行判断)
9091
+ 1 当前分组为隐藏时,标题就设置为隐藏
9092
+ 2 当前分组为显示时,其他分组只要有一个是显示,就显示该分组标题
9093
+ 3 当前分组为显示时,其他分组都隐藏,就隐藏该分组标题
9094
+ */
9095
+ sections.forEach((section, index) => {
9096
+ var tempSectionVisibleOns = sectionVisibleOns.slice();
9097
+ tempSectionVisibleOns.splice(index, 1);
9098
+ section.headingClassName = {
9099
+ "hidden": `!((${tempSectionVisibleOns.join(" || ") || 'false'}) && ${sectionVisibleOns[index]})`
9100
+ };
8856
9101
  });
8857
9102
 
8858
- const idFieldName = mainObject.idFieldName || "_id";
8859
- let valueField = mainObject.key_field || '_id';
8860
- const api = await getApi(mainObject, null, fields, { alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"` });
8861
- api.data.$term = "$term";
8862
- api.data.$self = "$$";
8863
- api.data.filter = "$filter";
8864
- api.data.pageSize = top || 10;
8865
- api.requestAdaptor = `
8866
- let selfData = JSON.parse(JSON.stringify(api.data.$self));
8867
- var filters = api.data.filter || ${JSON.stringify(filter)} || [];
8868
- const eventFetchInfo = selfData.fetchInfo;
8869
- const startDateExpr = "${calendarOptions.startDateExpr}";
8870
- const endDateExpr = "${calendarOptions.endDateExpr}";
8871
- const eventDurationFilters = [[endDateExpr, ">=", eventFetchInfo.start], [startDateExpr, "<=", eventFetchInfo.end]];
8872
- if(_.isEmpty(filters)){
8873
- filters = eventDurationFilters;
8874
- }else{
8875
- filters = [filters, 'and', eventDurationFilters]
8876
- }
9103
+ if (ctx.enableTabs) {
9104
+ // TODO: 以下sectionHeaderVisibleOn代码逻辑是为实现只有一个选项卡时给选项卡添加sectionHeaderVisibleOn样式类来把选项卡顶部卡头隐藏
9105
+ // 但是 amis filter过滤器有两个bug造成此功能不好实现:
9106
+ // 1.filter过滤器只支持对象数组,并不支持boolean或字符串数组,见: https://github.com/baidu/amis/issues/7078
9107
+ // 2.filter过滤器的返回结果无法进一步获取最终过滤后的数组长度,见:https://github.com/baidu/amis/issues/7077
9108
+ // let sectionHeaderVisibleOn = "false";
9109
+ // if(sectionVisibleOns.length){
9110
+ // sectionHeaderVisibleOn = "[" + sectionVisibleOns.join(",") + "]" + "|filter:equals:true.length > 1";
9111
+ // }
9112
+ // console.log("===sectionHeaderVisibleOn===", sectionHeaderVisibleOn);
9113
+ // sectionHeaderVisibleOn = "[true]|filter:equals:true.length > 1";
9114
+ // sectionHeaderVisibleOn = "false";
9115
+ // sectionHeaderVisibleOn = "[1,1,1]|filter:equals:1.length > 1";
9116
+ return [
9117
+ {
9118
+ "type": "tabs",
9119
+ // "className": {
9120
+ // "hiddenFormTabs": `!(${sectionHeaderVisibleOn})`
9121
+ // },
9122
+ "tabs": sections,
9123
+ "tabsMode": ctx.tabsMode
9124
+ }
9125
+ ]
9126
+ }
9127
+
9128
+ return sections;
9129
+ };
9130
+
9131
+ /*
9132
+ * @Author: baozhoutao@steedos.com
9133
+ * @Date: 2022-07-07 11:02:29
9134
+ * @LastEditors: baozhoutao@steedos.com
9135
+ * @LastEditTime: 2023-03-07 17:19:34
9136
+ * @Description:
9137
+ */
9138
+
9139
+ async function getFormBody(permissionFields, formFields, ctx){
9140
+ return await getSections(permissionFields, formFields, ctx);
9141
+ }
9142
+
9143
+ // lodash的defaultsDeep函数有bug,无法正确合并值为数值的节点,重写修正该函数
9144
+ // 源码出处:https://github.com/nodeutils/defaults-deep
9145
+ const defaultsDeep = (...args)=>{
9146
+ let output = {};
9147
+ toArray(args).reverse().forEach(item=> {
9148
+ mergeWith(output, item, (objectValue, sourceValue) => {
9149
+ return isArray(sourceValue) ? sourceValue : undefined;
9150
+ });
9151
+ });
9152
+ return output;
9153
+ };
9154
+
9155
+ function getBulkActions(objectSchema){
9156
+ return [
9157
+ {
9158
+ "type": "button",
9159
+ "level": "danger",
9160
+ "label": "批量删除",
9161
+ "actionType": "ajax",
9162
+ "confirmText": "确定要删除吗",
9163
+ "className": "hidden",
9164
+ "id": "batchDelete",
9165
+ "api": getBatchDelete(objectSchema.name),
9166
+ }
9167
+ // {
9168
+ // "label": "批量修改",
9169
+ // "actionType": "dialog",
9170
+ // "dialog": {
9171
+ // "title": "批量编辑",
9172
+ // "name": "sample-bulk-edit",
9173
+ // "body": {
9174
+ // "type": "form",
9175
+ // "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample/bulkUpdate2",
9176
+ // "controls": [
9177
+ // {
9178
+ // "type": "hidden",
9179
+ // "name": "ids"
9180
+ // },
9181
+ // {
9182
+ // "type": "text",
9183
+ // "name": "name",
9184
+ // "label": "Name"
9185
+ // }
9186
+ // ]
9187
+ // }
9188
+ // }
9189
+ // }
9190
+ ]
9191
+ }
8877
9192
 
8878
- if(api.data.$self.additionalFilters){
8879
- filters.push(api.data.$self.additionalFilters)
9193
+ async function getObjectCRUD(objectSchema, fields, options){
9194
+ // console.time('getObjectCRUD');
9195
+ const { top, perPage, showDisplayAs = false, displayAs, crudClassName = "" } = options;
9196
+ const nonpaged = objectSchema.paging && objectSchema.paging.enabled === false;
9197
+ const isTreeObject = objectSchema.enable_tree;
9198
+ const bulkActions = getBulkActions(objectSchema);
9199
+ const bodyProps = {
9200
+ // toolbar: getToolbar(),
9201
+ // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
9202
+ headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
9203
+ footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
9204
+ disableStatistics: options.queryCount === false
9205
+ }),
9206
+ filter: options.filterVisible !== false && await getObjectFilter(objectSchema, fields, options),
9207
+ };
9208
+ if(options.formFactor !== 'SMALL' || ["split"].indexOf(options.displayAs) == -1){
9209
+ Object.assign(bodyProps, {
9210
+ bulkActions: options.bulkActions != false ? bulkActions : false
9211
+ });
8880
9212
  }
8881
-
8882
- var pageSize = api.data.pageSize || 10;
8883
- var pageNo = api.data.pageNo || 1;
8884
- var skip = (pageNo - 1) * pageSize;
8885
- var orderBy = api.data.orderBy || '';
8886
- var orderDir = api.data.orderDir || '';
8887
- var sort = orderBy + ' ' + orderDir;
8888
- sort = orderBy ? sort : "${sort}";
8889
- var allowSearchFields = ${JSON.stringify(searchableFields)};
8890
- if(api.data.$term){
8891
- filters = [["name", "contains", "'+ api.data.$term +'"]];
8892
- }else if(selfData.op === 'loadOptions' && selfData.value){
8893
- filters = [["${valueField.name}", "=", selfData.value]];
9213
+ // yml里配置的 不分页和enable_tree:true 优先级最高,组件中输入的top次之。
9214
+ options.queryCount = true;
9215
+ if(nonpaged || isTreeObject){
9216
+ options.top = 5000;
9217
+ bodyProps.footerToolbar = [];
9218
+ options.queryCount = true; // 禁止翻页的时候, 需要查找总数
9219
+ }else if(top){
9220
+ bodyProps.footerToolbar = [];
9221
+ if(options.isRelated){
9222
+ options.queryCount = true;
9223
+ }else {
9224
+ options.queryCount = false;
9225
+ }
8894
9226
  }
8895
- var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
9227
+ // console.log(`getObjectHeaderToolbar====2===>`, options.filterVisible)
9228
+ bodyProps.headerToolbar = getObjectHeaderToolbar(objectSchema, options.formFactor, {
9229
+ showDisplayAs,
9230
+ hiddenCount: options.queryCount === false,
9231
+ headerToolbarItems: options.headerToolbarItems,
9232
+ filterVisible: options.filterVisible
9233
+ });
8896
9234
 
8897
- if(searchableFilter.length > 0){
8898
- if(filters.length > 0 ){
8899
- filters = [filters, 'and', searchableFilter];
8900
- }else{
8901
- filters = searchableFilter;
8902
- }
8903
- }
8904
9235
 
8905
- if(allowSearchFields){
8906
- allowSearchFields.forEach(function(key){
8907
- const keyValue = selfData[key];
8908
- if(_.isString(keyValue)){
8909
- filters.push([key, "contains", keyValue]);
8910
- }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8911
- filters.push([key, "=", keyValue]);
9236
+ let body = null;
9237
+ const id = `listview_${objectSchema.name}`;
9238
+ if(options.formFactor === 'SMALL' && false){
9239
+ delete bodyProps.bulkActions;
9240
+ delete bodyProps.headerToolbar;
9241
+ delete bodyProps.footerToolbar;
9242
+ const card = await getCardSchema(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: objectSchema.NAME_FIELD_KEY || 'name'}, options, {actions: false}));
9243
+ body = Object.assign({}, card , {
9244
+ type: 'crud',
9245
+ primaryField: '_id',
9246
+ id: id,
9247
+ name: id,
9248
+ keepItemSelectionOnPageChange: false,
9249
+ api: await getTableApi(objectSchema, fields, options),
9250
+ hiddenOn: options.tableHiddenOn,
9251
+ },
9252
+ bodyProps
9253
+ );
9254
+ }else {
9255
+ let labelFieldName = objectSchema.NAME_FIELD_KEY || 'name';
9256
+ // organizations 对象的历史遗留问题, fullname 被标记为了 名称字段. 在此处特殊处理.
9257
+ if(objectSchema.name === 'organizations'){
9258
+ labelFieldName = 'name';
9259
+ }
9260
+ const table = await getTableSchema$1(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: labelFieldName, permissions:objectSchema.permissions,enable_inline_edit:objectSchema.enable_inline_edit}, options));
9261
+ delete table.mode;
9262
+ //image与avatar需要在提交修改时特别处理
9263
+ const imageNames = ___default__default.compact(___default__default.map(___default__default.filter(fields, (field) => ["image","avatar"].includes(field.type)), 'name'));
9264
+ const quickSaveApiRequestAdaptor = `
9265
+ var graphqlOrder = "";
9266
+ var imageNames = ${JSON.stringify(imageNames)};
9267
+ api.data.rowsDiff.forEach(function (item, index) {
9268
+ for(key in item){
9269
+ if(_.includes(imageNames, key)){
9270
+ if(typeof item[key] == "string"){
9271
+ const match = item[key].match(/\\/([^\\/]+)$/);
9272
+ item[key] = match && match.length > 1?match[1]:"";
9273
+ }else{
9274
+ item[key] = _.map(item[key], function(ele){
9275
+ const match = ele.match(/\\/([^\\/]+)$/);
9276
+ return match && match.length > 1?match[1]:"";
9277
+ })
9278
+ }
8912
9279
  }
9280
+ }
9281
+ const itemOrder = 'update' + index + ':' + api.data.objectName + '__update(id:"' + item._id + '", doc:' + JSON.stringify(JSON.stringify(_.omit(item, '_id'))) + ') {_id}';
9282
+ graphqlOrder += itemOrder;
8913
9283
  })
8914
- }
8915
-
8916
- if(selfData.__keywords && allowSearchFields){
8917
- const keywordsFilters = [];
8918
- allowSearchFields.forEach(function(key, index){
8919
- const keyValue = selfData.__keywords;
8920
- if(keyValue){
8921
- keywordsFilters.push([key, "contains", keyValue]);
8922
- if(index < allowSearchFields.length - 1){
8923
- keywordsFilters.push('or');
8924
- }
9284
+ graphqlOrder = 'mutation {' + graphqlOrder + '}';
9285
+ return {
9286
+ ...api,
9287
+ data: {
9288
+ query: graphqlOrder
8925
9289
  }
8926
- })
8927
- filters.push(keywordsFilters);
8928
- }
8929
- api.data.query = api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim());
8930
- delete api.data.$term;
8931
- delete api.data.filter;
8932
- delete api.data.pageSize;
8933
- delete api.data.pageNo;
8934
- delete api.data.orderBy;
8935
- delete api.data.orderDir;
8936
- return api;
8937
- `;
8938
- api.adaptor = `
8939
- window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8940
- const setDataToComponentId = "${setDataToComponentId}";
8941
- if(setDataToComponentId){
8942
- SteedosUI.getRef(api.body.$self.scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8943
- }
8944
- const rows = payload.data.rows || [];
8945
- const selfData = api.data.$self;
8946
- const events = rows.map(function(n){
8947
- return {
8948
- id: n["${idFieldName}"],
8949
- title: n["${calendarOptions.textExpr}"],
8950
- start: n["${calendarOptions.startDateExpr}"],
8951
- end: n["${calendarOptions.endDateExpr}"],
8952
- allDay: n["${calendarOptions.allDayExpr}"],
8953
- extendedProps: n
8954
- }
8955
- });
8956
- const successCallback = selfData.successCallback;
8957
- const failureCallback = selfData.failureCallback;
8958
- successCallback(events);
8959
- return payload;
8960
- `;
8961
- return api;
8962
- }
9290
+ }
9291
+ `;
8963
9292
 
8964
- function getCalendarRecordPermissionsApi(mainObject, recordId) {
8965
- const api = getRecordPermissionsApi(mainObject, recordId, { alias: 'rows', limit: 1, fields: ["allowEdit"] });
8966
- api.data.$self = "$$";
8967
- api.adaptor = `
8968
- const rows = payload.data.rows || [];
8969
- const selfData = api.data.$self;
8970
- const revert = selfData.revert;
8971
- const recordPermissions = rows[0] && rows[0].recordPermissions;
8972
- const editable = !!(recordPermissions && recordPermissions.allowEdit);
8973
- if(!editable){
8974
- // 没有权限时还原
8975
- revert && revert();
9293
+ body = Object.assign({}, table, {
9294
+ type: 'crud',
9295
+ primaryField: '_id',
9296
+ affixHeader: false,
9297
+ id: id,
9298
+ name: id,
9299
+ keepItemSelectionOnPageChange: true,
9300
+ api: await getTableApi(objectSchema, fields, options),
9301
+ hiddenOn: options.tableHiddenOn,
9302
+ autoFillHeight: options.isRelated ? false : true,
9303
+ className: `flex-auto ${crudClassName || ""}`,
9304
+ bodyClassName: "bg-white",
9305
+ crudClassName: crudClassName,
9306
+ quickSaveApi: {
9307
+ url: `\${context.rootUrl}/graphql`,
9308
+ method: "post",
9309
+ dataType: "json",
9310
+ headers: {
9311
+ Authorization: "Bearer ${context.tenantId},${context.authToken}",
9312
+ },
9313
+ requestAdaptor: quickSaveApiRequestAdaptor,
9314
+ },
9315
+ rowClassNameExpr: options.rowClassNameExpr
9316
+ },
9317
+ bodyProps,
9318
+ );
8976
9319
  }
8977
- payload.data.editable = editable;
8978
- return payload;
8979
- `;
8980
- return api;
8981
- }
8982
-
8983
- function getCalendarRecordSaveApi(object, calendarOptions) {
8984
- const formData = {};
8985
- const idFieldName = object.idFieldName || "_id";
8986
- formData[idFieldName] = "${event.data.event.id}";
8987
- const nameFieldKey = object.NAME_FIELD_KEY || "name";
8988
- formData[nameFieldKey] = "${event.data.event.title}";
8989
- formData[calendarOptions.startDateExpr] = "${event.data.event.start}";
8990
- formData[calendarOptions.endDateExpr] = "${event.data.event.end}";
8991
- formData[calendarOptions.allDayExpr] = "${event.data.event.allDay}";
8992
- // formData[calendarOptions.textExpr] = "${event.data.event.title}";
8993
- const apiData = {
8994
- objectName: "${objectName}",
8995
- $: formData,
8996
- $self: "$$"
8997
- };
8998
- const saveDataTpl = `
8999
- const formData = api.data.$;
9000
- const objectName = api.data.objectName;
9001
- let query = \`mutation{record: \${objectName}__update(id: "\${formData.${idFieldName}}", doc: {__saveData}){${idFieldName}}}\`;
9002
- delete formData.${idFieldName};
9003
- let __saveData = JSON.stringify(JSON.stringify(formData));
9004
- `;
9005
- const requestAdaptor = `
9006
- ${saveDataTpl}
9007
- api.data.query = query.replace('{__saveData}', __saveData);
9008
- return api;
9009
- `;
9010
9320
 
9011
- return {
9012
- method: 'post',
9013
- url: getApi$2(),
9014
- data: apiData,
9015
- requestAdaptor: requestAdaptor,
9016
- adaptor: `
9017
- if(payload.errors){
9018
- payload.status = 2;
9019
- payload.msg = payload.errors[0].message;
9020
- const revert = api.data.$self.event.data.revert;
9021
- revert && revert();
9321
+ const defaults = options.defaults;
9322
+ if (defaults) {
9323
+ const listSchema = defaults.listSchema || {};
9324
+ body = defaultsDeep({}, listSchema, body);
9325
+ const headerSchema = defaults.headerSchema;
9326
+ const footerSchema = defaults.footerSchema;
9327
+ if (headerSchema || footerSchema) {
9328
+ let wrappedBody = [body];
9329
+ if (headerSchema) {
9330
+ if(___default__default.isArray(headerSchema)){
9331
+ wrappedBody = ___default__default.union(headerSchema,wrappedBody);
9332
+ }
9333
+ else {
9334
+ wrappedBody.unshift(headerSchema);
9335
+ }
9022
9336
  }
9023
- return payload;
9024
- `,
9025
- headers: {
9026
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
9337
+ if (footerSchema) {
9338
+ if(___default__default.isArray(footerSchema)){
9339
+ wrappedBody = ___default__default.union(wrappedBody,footerSchema);
9340
+ }
9341
+ else {
9342
+ wrappedBody.push(footerSchema);
9343
+ }
9344
+ }
9345
+ body = wrappedBody;
9346
+ }
9347
+ }
9348
+ // console.timeEnd('getObjectCRUD');
9349
+ // TODO: data应该只留loaded,其他属性都改为从上层传递下来
9350
+ return {
9351
+ type: 'service',
9352
+ className: '',
9353
+ id: `service_${id}`,
9354
+ name: `page`,
9355
+ data: {
9356
+ objectName: objectSchema.name,
9357
+ // _id: null,
9358
+ recordPermissions: objectSchema.permissions,
9359
+ uiSchema: objectSchema,
9360
+ // loaded: false //crud接收适配器中设置为true,否则就是刷新浏览器第一次加载
9361
+ },
9362
+ body: body
9027
9363
  }
9028
- };
9029
9364
  }
9030
9365
 
9031
- /**
9032
- * 列表视图Calendar amisSchema
9033
- * @param {*} objectSchema 对象UISchema
9034
- * @returns amisSchema
9035
- */
9036
- async function getObjectCalendar(objectSchema, calendarOptions, options) {
9037
- const permissions = objectSchema.permissions;
9038
- if (!options) {
9039
- options = {};
9040
- }
9041
-
9042
- calendarOptions = Object.assign({}, DEFAULT_CALENDAR_OPTIONS, omitBy(calendarOptions, isNil));
9366
+ const getGlobalData = (mode)=>{
9367
+ const user = getSteedosAuth();
9368
+ return {mode: mode, user: user, spaceId: user.spaceId, userId: user.userId}
9369
+ };
9043
9370
 
9044
- const titleFields = calendarOptions.title || [
9045
- calendarOptions.startDateExpr,
9046
- calendarOptions.endDateExpr,
9047
- calendarOptions.allDayExpr,
9048
- calendarOptions.textExpr
9049
- ];
9050
- let fields = [];
9051
- each(titleFields, function (n) {
9052
- if (objectSchema.fields[n]) {
9053
- fields.push(objectSchema.fields[n]);
9371
+ const getFormFields = (objectSchema, formProps)=>{
9372
+ /**
9373
+ * fieldsExtend: 重写字段定义
9374
+ * fields: 包含的字段
9375
+ * excludedFields: 排除的字段
9376
+ */
9377
+ const { fieldsExtend, fields: includedFields, excludedFields } = formProps;
9378
+
9379
+ let fields = {};
9380
+ // 以uiSchema fields 为基础, 遍历字段, 并更新字段定义
9381
+ ___default__default.forEach(objectSchema.fields, (field, fieldName)=>{
9382
+ if(!lodash.has(field, "name")){
9383
+ field.name = fieldName;
9384
+ }
9385
+ if(fieldsExtend && fieldsExtend[fieldName]){
9386
+ fields[field.name] = Object.assign({}, field, fieldsExtend[fieldName], {name: field.name});
9387
+ }else {
9388
+ fields[field.name] = field;
9054
9389
  }
9055
9390
  });
9056
9391
 
9057
- if (objectSchema.fields[calendarOptions.allDayExpr]) {
9058
- fields.push(objectSchema.fields[calendarOptions.allDayExpr]);
9392
+ if(!___default__default.isEmpty(includedFields) && ___default__default.isArray(includedFields)){
9393
+ const includedFieldsMap = {};
9394
+ ___default__default.each(includedFields, (fName, index)=>{
9395
+ if(fields[fName]){
9396
+ includedFieldsMap[fName] = Object.assign({}, fields[fName], {sort_no: index});
9397
+ }
9398
+ });
9399
+ fields = includedFieldsMap;
9059
9400
  }
9060
9401
 
9061
- let sort = options.sort;
9062
- if (!sort) {
9063
- const sortField = options.sortField;
9064
- const sortOrder = options.sortOrder;
9065
- if (sortField) {
9066
- let sortStr = sortField + ' ' + sortOrder || 'asc';
9067
- sort = sortStr;
9068
- }
9069
- }
9070
- let initialView = calendarOptions.currentView;
9071
- if (initialView) {
9072
- // day, week, month, agenda
9073
- switch (initialView) {
9074
- case "day":
9075
- initialView = "timeGridDay";
9076
- break;
9077
- case "week":
9078
- initialView = "timeGridWeek";
9079
- break;
9080
- case "month":
9081
- initialView = "dayGridMonth";
9082
- break;
9083
- case "agenda":
9084
- initialView = "listWeek";
9085
- break;
9086
- }
9087
- }
9088
- else {
9089
- initialView = "timeGridWeek";
9402
+ if(!___default__default.isEmpty(excludedFields) && ___default__default.isArray(excludedFields)){
9403
+ ___default__default.each(excludedFields, (fName)=>{
9404
+ delete fields[fName];
9405
+ });
9090
9406
  }
9091
9407
 
9092
- options.calendarOptions = calendarOptions;
9093
- const api = await getCalendarApi(objectSchema, fields, options);
9408
+ return lodash.sortBy(___default__default.values(fields), "sort_no");
9409
+ };
9094
9410
 
9095
- const onGetEventsScript = `
9096
- const api = ${JSON.stringify(api)};
9097
- event.data.calendarOptions = ${JSON.stringify(calendarOptions)};
9098
- doAction({
9099
- "actionType": 'ajax',
9100
- "args": {
9101
- "api": api
9411
+ async function getObjectForm(objectSchema, ctx){
9412
+ const { recordId, formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, tabId, appId, defaults } = ctx;
9413
+ const fields = ___default__default.values(objectSchema.fields);
9414
+ const formFields = getFormFields(objectSchema, ctx);
9415
+ const formSchema = defaults && defaults.formSchema || {};
9416
+ if(___default__default.has(formSchema, 'className')){
9417
+ formSchema.className = 'steedos-amis-form';
9418
+ }
9419
+ const amisSchema = {
9420
+ type: 'service',
9421
+ className: 'p-0',
9422
+ name: `page_edit_${recordId}`,
9423
+ api: await getEditFormInitApi(objectSchema, recordId, fields, ctx),
9424
+ data:{
9425
+ editFormInited: false
9102
9426
  },
9103
- });
9104
- `;
9427
+ // data: {global: getGlobalData('edit'), recordId: recordId, objectName: objectSchema.name, context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
9428
+ initApi: null,
9429
+ initFetch: null ,
9430
+ body: [defaultsDeep({}, formSchema, {
9431
+ type: "form",
9432
+ mode: layout,
9433
+ data: {
9434
+ "&": "${initialValues}"
9435
+ },
9436
+ labelAlign,
9437
+ persistData: false,
9438
+ resetAfterSubmit: true,
9439
+ preventEnterSubmit: true,
9440
+ promptPageLeave: true,
9441
+ canAccessSuperData: false,
9442
+ name: `form_edit_${recordId}`,
9443
+ debug: false,
9444
+ title: "",
9445
+ submitText: "", // amis 表单不显示提交按钮, 表单提交由项目代码接管
9446
+ api: await getSaveApi(objectSchema, recordId, fields, ctx),
9447
+ initFetch: recordId != 'new',
9448
+ body: await getFormBody(fields, formFields, ctx),
9449
+ panelClassName:'m-0 sm:rounded-lg shadow-none border-none',
9450
+ bodyClassName: 'p-0',
9451
+ className: 'steedos-amis-form',
9452
+ hiddenOn: "${editFormInited != true}",
9453
+ onEvent: {
9454
+ "submitSucc": {
9455
+ "weight": 0,
9456
+ "actions": [
9457
+ {
9458
+ "actionType": "broadcast",
9459
+ "args": {
9460
+ "eventName": `@data.changed.${objectSchema.name}`
9461
+ },
9462
+ "data": {
9463
+ "objectName": `${objectSchema.name}`,
9464
+ "displayAs": "${displayAs}"
9465
+ }
9466
+ },
9467
+ {
9468
+ "actionType": "broadcast",
9469
+ "args": {
9470
+ "eventName": "@data.changed.${_master.objectName}"
9471
+ },
9472
+ "data": {
9473
+ "objectName": "${_master.objectName}",
9474
+ "_isRelated": "${_isRelated || _master._isRelated}"
9475
+ },
9476
+ "expression": `\${_master.objectName != '${objectSchema.name}' && _master.objectName}`
9477
+ },
9478
+ // {
9479
+ // "actionType": "custom",
9480
+ // "script": "debugger;"
9481
+ // },
9482
+ // {
9483
+ // "args": {},
9484
+ // "actionType": "closeDialog"
9485
+ // }
9486
+ ]
9487
+ }
9488
+ }
9489
+ })]
9490
+ };
9491
+ if(formSchema.id){
9492
+ amisSchema.id = `service-${formSchema.id}`;
9493
+ }
9494
+ return amisSchema;
9495
+ }
9105
9496
 
9106
- const onSelectScript = `
9107
- const data = event.data;
9108
- const doc = {};
9109
- doc["${calendarOptions.startDateExpr}"] = data.start;
9110
- doc["${calendarOptions.endDateExpr}"] = data.end;
9111
- doc["${calendarOptions.allDayExpr}"] = data.allDay;
9112
- doc["${calendarOptions.textExpr}"] = data.title;
9113
- // ObjectForm会认作用域下的变量值
9114
- // TODO: 待组件支持initValues属性后应该改掉,不应该通过data直接传值
9115
- // TODO: 全天事件属性传入doc了但是没有生效,需要手动在ObjectForm中勾选全天事件
9116
- const title = "新建 ${objectSchema.label}";
9117
- doAction(
9118
- {
9119
- "actionType": "dialog",
9120
- "dialog": {
9121
- "type": "dialog",
9122
- "title": title,
9123
- "body": [
9124
- {
9125
- "type": "steedos-object-form",
9126
- "objectApiName": "\${objectName}",
9127
- "mode": "edit",
9128
- "defaultData": doc,
9129
- "onEvent": {
9130
- "submitSucc": {
9131
- "weight": 0,
9497
+ async function getObjectDetail(objectSchema, recordId, ctx){
9498
+ const { formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, formInitProps } = ctx;
9499
+ const fields = ___default__default.values(objectSchema.fields);
9500
+ const formFields = getFormFields(objectSchema, ctx);
9501
+ const serviceId = `service_detail_page`;
9502
+ return {
9503
+ type: 'service',
9504
+ name: `page_readonly_${recordId}`,
9505
+ id: serviceId,
9506
+ data: {global: getGlobalData('read'), context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
9507
+ api: await getReadonlyFormInitApi(objectSchema, recordId, fields, formInitProps),
9508
+ body: [
9509
+ {
9510
+ "type": "wrapper", //form 的 hiddenOn 会导致 form onEvent 异常, 使用wrapper包裹一次form,并在wrapper上控制显隐
9511
+ hiddenOn: "${recordLoaded != true}",
9512
+ "className": "p-0 m-0",
9513
+ "body": {
9514
+ type: "form",
9515
+ mode: layout,
9516
+ labelAlign,
9517
+ persistData: false,
9518
+ promptPageLeave: false,
9519
+ name: `form_readonly_${recordId}`,
9520
+ debug: false,
9521
+ title: "",
9522
+ data: {
9523
+ "formData": "$$"
9524
+ },
9525
+ wrapWithPanel: false,
9526
+ body: await getFormBody(map(fields, (field)=>{field.readonly = true; return field;}), map(formFields, (field)=>{field.readonly = true; return field;}), Object.assign({}, ctx, {showSystemFields: true})),
9527
+ className: 'steedos-amis-form bg-white',
9528
+ actions: [], // 不显示表单默认的提交按钮
9529
+ onEvent: {
9530
+ [`@data.changed.${objectSchema.name}`]: { // 由于amis service 组件的 onEvent 存在bug ,此处借助form来刷新 上层 service https://github.com/baidu/amis/issues/6294
9132
9531
  "actions": [
9133
9532
  {
9533
+ "actionType": "reload",
9534
+ "componentId": serviceId,
9535
+ "expression": "this.__deletedRecord != true"
9536
+ },
9537
+ {
9538
+ // "args": {
9539
+ // "url": "/app/${appId}/${objectName}/grid/${side_listview_id}",
9540
+ // "blank": false
9541
+ // },
9134
9542
  "actionType": "custom",
9135
- "script": "event.data.view?.calendar.refetchEvents();"
9543
+ "script": "Steedos.goBack()",
9544
+ "expression": "this.__deletedRecord === true"
9136
9545
  }
9137
9546
  ]
9138
9547
  }
9139
9548
  }
9140
- }
9141
- ],
9142
- "closeOnEsc": false,
9143
- "closeOnOutside": false,
9144
- "showCloseButton": true,
9145
- "size": "lg"
9146
- }
9147
- });
9148
- `;
9149
-
9150
- const onEventClickScript = `
9151
- const data = event.data;
9152
- const eventData = data.event;
9153
- const appId = data.appId;
9154
- const objectName = data.objectName;
9155
- const eventId = data.event && data.event.id;
9156
- doAction({
9157
- "actionType": "dialog",
9158
- "dialog": {
9159
- "type": "dialog",
9160
- "title": "",
9161
- "body": [
9162
- {
9163
- "type": "steedos-record-detail",
9164
- "objectApiName": "\${objectName}",
9165
- "recordId": data.event && data.event.id
9166
- }
9167
- ],
9168
- "closeOnEsc": false,
9169
- "closeOnOutside": false,
9170
- "showCloseButton": true,
9171
- "size": "lg",
9172
- "actions": []
9173
- }
9174
- });
9175
- `;
9176
-
9177
- const recordId = "${event.id}";
9178
- const recordPermissionsApi = getCalendarRecordPermissionsApi(objectSchema, recordId);
9179
- const recordSaveApi = getCalendarRecordSaveApi(objectSchema, calendarOptions);
9180
-
9181
- const businessHours = {
9182
- daysOfWeek: [1, 2, 3, 4, 5],
9183
- startTime: '08:00',
9184
- endTime: '18:00',
9185
- };
9186
- if (!isEmpty(calendarOptions.startDayHour)) {
9187
- businessHours.startTime = `${calendarOptions.startDayHour}:00`;
9188
- }
9189
- if (!isEmpty(calendarOptions.endDayHour)) {
9190
- businessHours.endTime = `${calendarOptions.endDayHour}:00`;
9191
- }
9192
-
9193
- const onEvent = {
9194
- "getEvents": {
9195
- "weight": 0,
9196
- "actions": [
9197
- {
9198
- "componentId": "",
9199
- "args": {
9200
- },
9201
- "actionType": "custom",
9202
- "script": onGetEventsScript
9203
- }
9204
- ]
9205
- },
9206
- "select": {
9207
- "weight": 0,
9208
- "actions": [
9209
- {
9210
- "componentId": "",
9211
- "args": {
9212
- },
9213
- "actionType": "custom",
9214
- "script": onSelectScript
9215
- }
9216
- ]
9217
- },
9218
- "eventClick": {
9219
- "weight": 0,
9220
- "actions": [
9221
- {
9222
- "componentId": "",
9223
- "args": {
9224
- },
9225
- "actionType": "custom",
9226
- "script": onEventClickScript
9227
- }
9228
- ]
9229
- },
9230
- "eventAdd": {
9231
- "weight": 0,
9232
- "actions": [
9233
- {
9234
- "componentId": "",
9235
- "args": {
9236
9549
  },
9237
- "actionType": "custom",
9238
- "script": "console.log('eventAdd'); console.log(event);"
9239
- }
9240
- ]
9241
- },
9242
- "eventChange": {
9243
- "weight": 0,
9244
- "actions": [
9245
- {
9246
- "actionType": 'ajax',
9247
- "args": {
9248
- "api": recordPermissionsApi
9249
- }
9250
- },
9251
- {
9252
- "actionType": "toast",
9253
- "expression": "!event.data.editable",
9254
- "args": {
9255
- "msgType": "error",
9256
- "msg": "您没有编辑该记录的权限!",
9257
- "position": "top-center"
9258
9550
  }
9259
- },
9260
- {
9261
- "actionType": 'ajax',
9262
- "expression": "event.data.editable",
9263
- "args": {
9264
- "api": recordSaveApi,
9265
- "messages": {
9266
- "success": objectSchema.label + "修改成功",
9267
- "failed": objectSchema.label + "修改失败!"
9551
+ ],
9552
+ onEvent: {
9553
+ "fetchInited": {
9554
+ "weight": 0,
9555
+ "actions": [
9556
+ {
9557
+ actionType: 'broadcast',
9558
+ eventName: "recordLoaded",
9559
+ args: {
9560
+ eventName: "recordLoaded"
9561
+ },
9562
+ data: {
9563
+ objectName: "${event.data.__objectName}",
9564
+ record: "${event.data.__record}"
9565
+ },
9566
+ expression: "${event.data.__response.error != true}"
9567
+ },
9568
+ {
9569
+ "actionType": "setValue",
9570
+ "args": {
9571
+ value: {
9572
+ "recordLoaded": true,
9573
+ }
9574
+ },
9575
+ expression: "${event.data.__response.error != true}"
9268
9576
  }
9577
+ ]
9269
9578
  }
9270
9579
  }
9271
- ]
9272
- },
9273
- "eventRemove": {
9274
- "weight": 0,
9275
- "actions": [
9276
- {
9277
- "componentId": "",
9278
- "args": {
9279
- },
9280
- "actionType": "custom",
9281
- "script": "console.log('eventRemove'); console.log(event);"
9282
- }
9283
- ]
9284
- },
9285
- "eventsSet": {
9286
- "weight": 0,
9287
- "actions": [
9288
- {
9289
- "componentId": "",
9290
- "args": {
9291
- },
9292
- "actionType": "custom",
9293
- "script": "console.log('eventsSet'); console.log(event);"
9294
- }
9295
- ]
9296
- }
9297
- };
9298
-
9299
- Object.assign(onEvent, options.onEvent);
9300
-
9301
- const config = options.config || {};
9302
- if(config.eventContent && typeof config.eventContent === "string"){
9303
- const hasReturn = /\breturn\b/.test(config.eventContent);
9304
- if(hasReturn){
9305
- try {
9306
- // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
9307
- let fn = new Function("arg", config.eventContent);
9308
- config.eventContent = fn;
9309
- } catch (e) {
9310
- console.warn(e);
9311
- }
9312
- }
9313
- }
9314
-
9315
- if(config.noEventsContent && typeof config.noEventsContent === "string"){
9316
- const hasReturn = /\breturn\b/.test(config.noEventsContent);
9317
- if(hasReturn){
9318
- try {
9319
- // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
9320
- let fn = new Function("arg", config.noEventsContent);
9321
- config.noEventsContent = fn;
9322
- } catch (e) {
9323
- console.warn(e);
9324
- }
9325
9580
  }
9326
- }
9327
-
9328
- const amisSchema = {
9329
- "type": "steedos-fullcalendar",
9330
- "label": "",
9331
- "name": "fullcalendar",
9332
- "placeholder":"${additionalFilters}",//用于触发reload
9333
- "editable": permissions.allowEdit,
9334
- "selectable": permissions.allowCreate,
9335
- "selectMirror": permissions.allowCreate,
9336
- "initialView": initialView,
9337
- "businessHours": businessHours,
9338
- ...config,
9339
- "onEvent": onEvent
9340
- };
9341
- return amisSchema;
9342
9581
  }
9343
9582
 
9344
9583
  /*
@@ -9760,8 +9999,8 @@ async function getRelatedListSchema(
9760
9999
  /*
9761
10000
  * @Author: baozhoutao@steedos.com
9762
10001
  * @Date: 2022-07-05 15:55:39
9763
- * @LastEditors: baozhoutao@steedos.com
9764
- * @LastEditTime: 2023-04-28 11:11:29
10002
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
10003
+ * @LastEditTime: 2023-06-04 17:36:49
9765
10004
  * @Description:
9766
10005
  */
9767
10006
 
@@ -10092,7 +10331,8 @@ async function getListSchema(
10092
10331
  "requestAdaptor": listView.requestAdaptor,
10093
10332
  "adaptor": listView.adaptor,
10094
10333
  "headerToolbarItems": ctx.headerToolbarItems,
10095
- "filterVisible": ctx.filterVisible
10334
+ "filterVisible": ctx.filterVisible,
10335
+ "rowClassNameExpr": ctx.rowClassNameExpr
10096
10336
  };
10097
10337
  return {
10098
10338
  uiSchema,
@@ -13682,11 +13922,11 @@ var SteedosSkeleton = function (props) {
13682
13922
  };
13683
13923
 
13684
13924
  var AmisObjectForm = function (props) { return __awaiter(void 0, void 0, void 0, function () {
13685
- var $schema, recordId, defaultData, mode, layout, labelAlign, appId, fieldsExtend, _a, excludedFields, _b, fields, _c, className, initApiRequestAdaptor, initApiAdaptor, apiRequestAdaptor, apiAdaptor, objectApiName, schemaKeys, formSchema, defaults, options, globalData, amisSchema, uiSchema, schema, schema, formData;
13925
+ var $schema, recordId, defaultData, mode, layout, labelAlign, appId, fieldsExtend, _a, excludedFields, _b, fields, _c, className, initApiRequestAdaptor, initApiAdaptor, apiRequestAdaptor, apiAdaptor, enableTabs, tabsMode, objectApiName, schemaKeys, formSchema, defaults, options, globalData, amisSchema, uiSchema, schema, schema, formData;
13686
13926
  return __generator(this, function (_d) {
13687
13927
  switch (_d.label) {
13688
13928
  case 0:
13689
- $schema = props.$schema, recordId = props.recordId, defaultData = props.defaultData, mode = props.mode, layout = props.layout, labelAlign = props.labelAlign, appId = props.appId, fieldsExtend = props.fieldsExtend, _a = props.excludedFields, excludedFields = _a === void 0 ? null : _a, _b = props.fields, fields = _b === void 0 ? null : _b, _c = props.className, className = _c === void 0 ? "" : _c, initApiRequestAdaptor = props.initApiRequestAdaptor, initApiAdaptor = props.initApiAdaptor, apiRequestAdaptor = props.apiRequestAdaptor, apiAdaptor = props.apiAdaptor;
13929
+ $schema = props.$schema, recordId = props.recordId, defaultData = props.defaultData, mode = props.mode, layout = props.layout, labelAlign = props.labelAlign, appId = props.appId, fieldsExtend = props.fieldsExtend, _a = props.excludedFields, excludedFields = _a === void 0 ? null : _a, _b = props.fields, fields = _b === void 0 ? null : _b, _c = props.className, className = _c === void 0 ? "" : _c, initApiRequestAdaptor = props.initApiRequestAdaptor, initApiAdaptor = props.initApiAdaptor, apiRequestAdaptor = props.apiRequestAdaptor, apiAdaptor = props.apiAdaptor, enableTabs = props.enableTabs, tabsMode = props.tabsMode;
13690
13930
  objectApiName = props.objectApiName || "space_users";
13691
13931
  schemaKeys = difference(keys($schema), ["type", "mode", "layout", "defaultData"]);
13692
13932
  formSchema = pick(props, schemaKeys);
@@ -13716,7 +13956,9 @@ var AmisObjectForm = function (props) { return __awaiter(void 0, void 0, void 0,
13716
13956
  initApiRequestAdaptor: initApiRequestAdaptor,
13717
13957
  initApiAdaptor: initApiAdaptor,
13718
13958
  apiRequestAdaptor: apiRequestAdaptor,
13719
- apiAdaptor: apiAdaptor
13959
+ apiAdaptor: apiAdaptor,
13960
+ enableTabs: enableTabs,
13961
+ tabsMode: tabsMode
13720
13962
  }))];
13721
13963
  case 1:
13722
13964
  schema = _d.sent();
@@ -13754,14 +13996,14 @@ var AmisObjectForm = function (props) { return __awaiter(void 0, void 0, void 0,
13754
13996
  }); };
13755
13997
 
13756
13998
  var AmisObjectListView = function (props) { return __awaiter(void 0, void 0, void 0, function () {
13757
- var $schema, top, perPage, _a, showHeader, data, defaultData, _b, className, crudClassName, _c, showDisplayAs, sideSchema, _e, filterVisible, headerToolbarItems, headerSchema, ctx, listName, defaults, objectApiName, displayAs, formFactor, isMobile, uiSchema, listView, schemaKeys, listSchema, setDataToComponentId, amisSchemaData, listViewId, listViewSchemaProps, serviceData;
13999
+ var $schema, top, perPage, _a, showHeader, data, defaultData, _b, className, crudClassName, _c, showDisplayAs, sideSchema, _e, filterVisible, headerToolbarItems, rowClassNameExpr, headerSchema, ctx, listName, defaults, objectApiName, displayAs, formFactor, isMobile, uiSchema, listView, schemaKeys, listSchema, setDataToComponentId, amisSchemaData, listViewId, listViewSchemaProps, serviceData;
13758
14000
  var _f;
13759
14001
  return __generator(this, function (_g) {
13760
14002
  switch (_g.label) {
13761
14003
  case 0:
13762
14004
  // console.time('AmisObjectListView')
13763
14005
  console.log("AmisObjectListView props", props);
13764
- $schema = props.$schema, top = props.top, perPage = props.perPage, _a = props.showHeader, showHeader = _a === void 0 ? true : _a, data = props.data, defaultData = props.defaultData, _b = props.className, className = _b === void 0 ? "" : _b, crudClassName = props.crudClassName, _c = props.showDisplayAs, showDisplayAs = _c === void 0 ? false : _c, sideSchema = props.sideSchema, props.columnsTogglable, _e = props.filterVisible, filterVisible = _e === void 0 ? true : _e, headerToolbarItems = props.headerToolbarItems;
14006
+ $schema = props.$schema, top = props.top, perPage = props.perPage, _a = props.showHeader, showHeader = _a === void 0 ? true : _a, data = props.data, defaultData = props.defaultData, _b = props.className, className = _b === void 0 ? "" : _b, crudClassName = props.crudClassName, _c = props.showDisplayAs, showDisplayAs = _c === void 0 ? false : _c, sideSchema = props.sideSchema, props.columnsTogglable, _e = props.filterVisible, filterVisible = _e === void 0 ? true : _e, headerToolbarItems = props.headerToolbarItems, rowClassNameExpr = props.rowClassNameExpr;
13765
14007
  headerSchema = props.headerSchema;
13766
14008
  ctx = props.ctx;
13767
14009
  listName = (defaultData === null || defaultData === void 0 ? void 0 : defaultData.listName) || (data === null || data === void 0 ? void 0 : data.listName) || (props === null || props === void 0 ? void 0 : props.listName);
@@ -13842,7 +14084,7 @@ var AmisObjectListView = function (props) { return __awaiter(void 0, void 0, voi
13842
14084
  }
13843
14085
  amisSchemaData = Object.assign({}, data, defaultData);
13844
14086
  listViewId = (ctx === null || ctx === void 0 ? void 0 : ctx.listViewId) || amisSchemaData.listViewId;
13845
- listViewSchemaProps = __assign$2(__assign$2({ top: top, perPage: perPage, showHeader: showHeader, defaults: defaults }, ctx), { listViewId: listViewId, setDataToComponentId: setDataToComponentId, filterVisible: filterVisible, showDisplayAs: showDisplayAs, displayAs: displayAs, headerToolbarItems: headerToolbarItems });
14087
+ listViewSchemaProps = __assign$2(__assign$2({ top: top, perPage: perPage, showHeader: showHeader, defaults: defaults }, ctx), { listViewId: listViewId, setDataToComponentId: setDataToComponentId, filterVisible: filterVisible, showDisplayAs: showDisplayAs, displayAs: displayAs, headerToolbarItems: headerToolbarItems, rowClassNameExpr: rowClassNameExpr });
13846
14088
  if (!headerSchema) {
13847
14089
  headerSchema = getObjectListHeader$1(uiSchema, listName, ctx);
13848
14090
  }