@steedos-widgets/amis-lib 1.2.14 → 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.
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _$1 from 'lodash';
2
- import ___default, { isEmpty, isArray, each, find, endsWith, cloneDeep, forEach, includes, get, toArray, mergeWith, map, isBoolean, omitBy, isNil, isString, union, has, slice, defaultsDeep as defaultsDeep$1, isObject as isObject$1, filter, startsWith } from 'lodash';
2
+ import ___default, { isEmpty, isArray, each, find, endsWith, cloneDeep, forEach, includes, get, isBoolean, omitBy, isNil, toArray, mergeWith, map, isString, union, has, slice, defaultsDeep as defaultsDeep$1, isObject as isObject$1, filter, startsWith } from 'lodash';
3
3
  import { Router as Router$1, getSteedosAuth as getSteedosAuth$1, lookupToAmis as lookupToAmis$1, fetchAPI as fetchAPI$1 } from '@steedos-widgets/amis-lib';
4
4
  import isPlainObject from 'lodash/isPlainObject';
5
5
 
@@ -1386,8 +1386,8 @@ const parseSingleExpression = function (func, formData, dataPath, global, userSe
1386
1386
  /*
1387
1387
  * @Author: baozhoutao@steedos.com
1388
1388
  * @Date: 2022-11-01 15:51:00
1389
- * @LastEditors: Please set LastEditors
1390
- * @LastEditTime: 2023-04-26 11:52:04
1389
+ * @LastEditors: liaodaxue
1390
+ * @LastEditTime: 2023-06-06 11:12:33
1391
1391
  * @Description:
1392
1392
  */
1393
1393
 
@@ -1470,7 +1470,7 @@ const getSchema$4 = async (uiSchema, ctx) => {
1470
1470
  "isLookup": "${isLookup}",
1471
1471
  "listName": "${listName}"
1472
1472
  },
1473
- "title": "新建 ${uiSchema.label}",
1473
+ "title": "新建 ${uiSchema.label | raw}",
1474
1474
  "body": [
1475
1475
  {
1476
1476
  "type": "service",
@@ -5443,6 +5443,7 @@ async function lookupToAmisPicker(field, readonly, ctx){
5443
5443
  pickerSchema = await getTableSchema$1(tableFields, {
5444
5444
  labelFieldName: refObjectConfig.NAME_FIELD_KEY,
5445
5445
  top: top,
5446
+ isLookup: true,
5446
5447
  ...ctx
5447
5448
  });
5448
5449
 
@@ -6022,7 +6023,7 @@ const getAmisFileReadonlySchema = (steedosField)=>{
6022
6023
  return {
6023
6024
  type: amisFieldType,
6024
6025
  tpl: `
6025
- <% let fileData = data.${steedosField.name}; if (fileData) { %>
6026
+ <% let fileData = data._display.${steedosField.name}; if (fileData) { %>
6026
6027
  <% if(!Array.isArray(fileData)){ fileData = [fileData]} %>
6027
6028
  <% fileData.forEach(function(item) { %>
6028
6029
  <a href='<%= item.url %>' target='_self' class='block'><%= item.name %></a>
@@ -6063,7 +6064,6 @@ const getAmisFileEditSchema = (steedosField)=>{
6063
6064
  }
6064
6065
  }
6065
6066
  };
6066
-
6067
6067
  if(steedosField.multiple){
6068
6068
  convertData.multiple = true;
6069
6069
  convertData.joinValues = false;
@@ -6786,2219 +6786,2439 @@ var index = /*#__PURE__*/Object.freeze({
6786
6786
  getAmisStaticFieldType: getAmisStaticFieldType
6787
6787
  });
6788
6788
 
6789
- const API_CACHE = 100;
6789
+ /*
6790
+ * @Author: baozhoutao@steedos.com
6791
+ * @Date: 2022-08-04 10:42:49
6792
+ * @LastEditors: baozhoutao@steedos.com
6793
+ * @LastEditTime: 2022-08-25 10:28:47
6794
+ * @Description:
6795
+ */
6796
+ var config = {
6797
+ listView: {
6798
+ newRecordMode: 'modal',
6799
+ editRecordMode: 'modal',
6800
+ perPage: 20
6801
+ }
6802
+ };
6790
6803
 
6791
- function getReadonlyFormAdaptor(object, fields){
6792
- let scriptStr = '';
6793
- const selectFields = _$1.filter(fields, function(field){return field.name.indexOf('.') < 0 && ((field.type == 'select' && field.options) || ((field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to))});
6794
- const gridAndObjectFieldsName = _$1.map(_$1.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type === 'object' || field.type === 'grid')}), 'name');
6795
- _$1.each(selectFields, function(field){
6796
- if(!_$1.includes(OMIT_FIELDS, field.name)){
6797
- field.name;
6798
- if(field.options){
6799
- const options = JSON.stringify({options: field.options});
6800
- scriptStr = scriptStr + `var ${field.name}Options= (${options}).options;`;
6801
- }else if(field.optionsFunction){
6802
- scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`;
6803
- }else if(field._optionsFunction){
6804
- scriptStr = scriptStr + `var ${field.name}Options = eval(${field._optionsFunction})(api.data);`;
6805
- }
6806
- if(field.multiple){
6807
- scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`;
6808
- }else {
6809
- scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`;
6810
- scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`;
6804
+ async function getQuickEditSchema(field, options){
6805
+ const quickEditId = options.objectName + "_" + field.name + "QuickEdit";//定义快速编辑的表单id,用于setvalue传值
6806
+ var quickEditSchema = { body: [], id: quickEditId };
6807
+ if (field.disabled) {
6808
+ quickEditSchema = false;
6809
+ } else {
6810
+ var fieldSchema = await convertSFieldToAmisField(field, false, _$1.omit(options, 'buttons'));
6811
+ //存在属性上可编辑,实际不可编辑的字段,convertSFieldToAmisField函数可能会返回undefined,如summary
6812
+ if (!!fieldSchema) {
6813
+ quickEditSchema.body.push(fieldSchema);
6814
+ //以下字段使用_display的数据,因此在触发change等事件时对数据_display进行修改,以实现保存前的回显
6815
+ var TempDisplayField = ``;
6816
+ quickEditSchema.body[0].onEvent = {};
6817
+ const quickEditOnEvent = function (displayField) {
6818
+ const EventType = {
6819
+ "actions": [
6820
+ {
6821
+ "actionType": "custom",
6822
+ "script": `
6823
+ var _display = event.data._display;
6824
+ ${displayField}
6825
+ doAction({actionType: 'setValue', "args": {"value": {_display}},componentId: "${quickEditId}"});
6826
+ `
6827
+ }
6828
+ ]
6829
+ };
6830
+ return EventType;
6831
+ };
6832
+ switch (field.type) {
6833
+ //TODO:amis的picker组件直接点击选项x时不会触发change事件,待处理
6834
+ case "lookup":
6835
+ case "master_detail":
6836
+ if (field.multiple) {
6837
+ TempDisplayField = `
6838
+ _display["${field.name}"] = [];
6839
+ event.data.value.forEach(function(item,index){
6840
+ _display["${field.name}"].push(
6841
+ {
6842
+ "label": event.data.option[index].${quickEditSchema.body[0].labelField},
6843
+ "value": event.data.option[index]._id,
6844
+ "objectName": "${field.reference_to}"
6845
+ }
6846
+ )
6847
+ })
6848
+ `;
6849
+ } else {
6850
+ TempDisplayField = `
6851
+ _display["${field.name}"] = {
6852
+ "label": event.data.option.${quickEditSchema.body[0].labelField},
6853
+ "value": event.data._id,
6854
+ "objectName": "${field.reference_to}"
6855
+ }
6856
+ `;
6857
+ }
6858
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6859
+ break;
6860
+ case "select":
6861
+ TempDisplayField = `
6862
+ _display["${field.name}"] = event.data.selectedItems.label;
6863
+ `;
6864
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6865
+ break;
6866
+ case "percent":
6867
+ TempDisplayField = `
6868
+ _display["${field.name}"] = (event.data.value * 100).toFixed(${field.scale}) + '%';
6869
+ `;
6870
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6871
+ break;
6872
+ case "time":
6873
+ TempDisplayField = `
6874
+ _display["${field.name}"] = moment(event.data.value).utc().format('HH:mm');
6875
+ `;
6876
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6877
+ break;
6878
+ case "date":
6879
+ TempDisplayField = `
6880
+ _display["${field.name}"] = moment(event.data.value).utc().format('YYYY-MM-DD');
6881
+ `;
6882
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6883
+ break;
6884
+ case "datetime":
6885
+ TempDisplayField = `
6886
+ _display["${field.name}"] = moment(event.data.value).format('YYYY-MM-DD HH:mm');
6887
+ `;
6888
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6889
+ break;
6890
+ case "boolean":
6891
+ TempDisplayField = `
6892
+ _display["${field.name}"] = event.data.value?"√":"";
6893
+ `;
6894
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6895
+ break;
6896
+ case "number":
6897
+ case "currency":
6898
+ TempDisplayField = `
6899
+ _display["${field.name}"] = event.data.value?.toFixed(${field.scale});
6900
+ `;
6901
+ quickEditSchema.body[0].onEvent["change"] = quickEditOnEvent(TempDisplayField);
6902
+
6903
+ break;
6904
+ case "file":
6905
+ var removeDisplayField = ``;
6906
+ if (field.multiple) {
6907
+ TempDisplayField = `
6908
+ _display["${field.name}"].push({
6909
+ "name": event.data.result.name,
6910
+ "url": event.data.result.url,
6911
+ "type": event.data.item.type,
6912
+ "size": event.data.item.size
6913
+ });
6914
+ `;
6915
+ removeDisplayField = `
6916
+ _.remove(_display["${field.name}"], function(file){return file.url == event.data.item.url});
6917
+ `;
6918
+ } else {
6919
+ TempDisplayField = `
6920
+ _display["${field.name}"] = {
6921
+ "name": event.data.result.name,
6922
+ "url": event.data.result.url,
6923
+ "type": event.data.item.type,
6924
+ "size": event.data.item.size
6925
+ };
6926
+ `;
6927
+ removeDisplayField = `
6928
+ if(_display["${field.name}"].url == event.data.item.url){
6929
+ _display["${field.name}"] = {};
6930
+ }
6931
+ `;
6932
+ }
6933
+ quickEditSchema.body[0].onEvent["success"] = quickEditOnEvent(TempDisplayField);
6934
+ quickEditSchema.body[0].onEvent["remove"] = quickEditOnEvent(removeDisplayField);
6935
+ break;
6936
+ case "avatar":
6937
+ case "image":
6938
+ quickEditSchema.body[0].receiver.adaptor = `
6939
+ const { context } = api.body;
6940
+ var rootUrl = context.rootUrl + "/api/files/${field.type}s/";
6941
+ payload = {
6942
+ status: response.status == 200 ? 0 : response.status,
6943
+ msg: response.statusText,
6944
+ data: {
6945
+ value: rootUrl + payload._id,//为了实现图片crud的回显,需要将value从id改为url,当保存数据数据时,再在发送适配器内重新将id提取出来
6946
+ name: payload.original.name,
6947
+ url: rootUrl + payload._id,
6948
+ }
6949
+ }
6950
+ return payload;
6951
+ `;
6952
+ break;
6811
6953
  }
6812
- }
6813
- });
6814
-
6815
- // const refFields = _.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to});
6816
- // _.each(refFields, function(field){
6817
- // if(!_.includes(OMIT_FIELDS, field.name)){
6818
- // const valueField = field.reference_to_field || '_id';
6819
- // scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`
6820
- // if(field.multiple){
6821
- // scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`
6822
- // }else{
6823
- // scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`
6824
- // scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`
6825
- // }
6826
- // }
6827
- // })
6828
6954
 
6829
- return `
6830
- if(payload.data.data.length === 0){
6831
- return {
6832
- status: 2,
6833
- msg: "无法找到记录"
6834
- }
6835
- }
6836
- if(payload.data.data){
6837
- var data = payload.data.data[0];
6838
- var gridAndObjectFieldsName = ${JSON.stringify(gridAndObjectFieldsName)};
6839
- try{
6840
- ${scriptStr}
6841
- ${getScriptForAddUrlPrefixForImgFields(fields)}
6842
- ${getScriptForRewriteValueForFileFields(fields)}
6843
- }catch(e){
6844
- console.error(e)
6955
+ } else {
6956
+ quickEditSchema = false;
6845
6957
  }
6846
- // 原始记录
6847
- var record = _.cloneDeep(data);
6848
- try{
6849
- _.each(gridAndObjectFieldsName, function(name){
6850
- data[name] = data._display[name];
6851
- })
6852
- }catch(e){
6853
- console.error(e)
6958
+ //TODO:附件多选时会覆盖老数据,暂时禁用
6959
+ if(field.type == "file" && field.multiple){
6960
+ quickEditSchema = false;
6854
6961
  }
6855
- payload.data = data;
6856
- payload.data.__objectName = "${object.name}";
6857
- payload.data.__record = record;
6858
- window.postMessage(Object.assign({type: "record.loaded"}, {record: record}), "*")
6859
- }
6860
- if(payload.errors){
6861
- payload.status = 2;
6862
- payload.msg = payload.errors[0].message;
6863
6962
  }
6864
- return payload;
6865
- `
6963
+ return quickEditSchema;
6866
6964
  }
6867
6965
 
6868
- async function getReadonlyFormInitApi(object, recordId, fields, options){
6869
- return {
6870
- method: "post",
6871
- url: getApi$2()+"&recordId=${recordId}",
6872
- cache: API_CACHE,
6873
- // requestAdaptor: "console.log('getReadonlyFormInitApi requestAdaptor', api);return api;",
6874
- adaptor: getReadonlyFormAdaptor(object, fields),
6875
- data: await getFindOneQuery$1(object, recordId, fields, options),
6876
- headers: {
6877
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
6966
+ async function getTableColumns(fields, options){
6967
+ const columns = [{name: '_index',type: 'text', width: 32, placeholder: ""}];
6968
+ const allowEdit = options.permissions?.allowEdit && options.permissions?.modifyAllRecords && !options.isLookup && options.enable_inline_edit != false;
6969
+ for (const field of fields) {
6970
+ //增加quickEdit属性,实现快速编辑
6971
+ const quickEditSchema = allowEdit ? await getQuickEditSchema(field, options) : allowEdit;
6972
+ if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
6973
+ const previewFileScript = `
6974
+ var data = event.data;
6975
+ var file_name = data.versions ? data.name : "${field.label}";
6976
+ var file_id = data._id;
6977
+ SteedosUI.previewFile && SteedosUI.previewFile({file_name, file_id});
6978
+ `;
6979
+ columns.push({
6980
+ "type": "button",
6981
+ "label": `<%=data.versions ? data.name : "${field.label}"%>`,
6982
+ "className": "whitespace-nowrap",
6983
+ "level": "link",
6984
+ "quickEdit": quickEditSchema,
6985
+ "onEvent": {
6986
+ "click": {
6987
+ "actions": [
6988
+ {
6989
+ "args": {
6990
+ "api": {
6991
+ "url": "${context.rootUrl}/api/files/files/${versions[0]}?download=true",
6992
+ "method": "get",
6993
+ "headers": {
6994
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
6995
+ }
6996
+ }
6997
+ },
6998
+ "actionType": "download",
6999
+ "expression": "!!!window?.nw?.require"//浏览器上直接下载
7000
+ },
7001
+ {
7002
+ "args": {},
7003
+ "actionType": "custom",
7004
+ "script": previewFileScript,
7005
+ "expression": "!!window?.nw?.require" //PC客户端预览附件
7006
+ }
7007
+ ]
7008
+ }
7009
+ }
7010
+ });
7011
+ }else if(field.type === 'toggle'){
7012
+ columns.push(Object.assign({}, {
7013
+ type: "switch",
7014
+ name: field.name,
7015
+ label: field.label,
7016
+ width: field.width,
7017
+ toggled: field.toggled,
7018
+ className:"whitespace-nowrap"
7019
+ }, field.amis, {name: field.name}));
7020
+ }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7021
+ columns.push(Object.assign({}, {
7022
+ type: "switch",
7023
+ name: field.name,
7024
+ label: field.label,
7025
+ width: field.width,
7026
+ toggled: field.toggled,
7027
+ quickEdit: quickEditSchema,
7028
+ className:"whitespace-nowrap",
7029
+ ...getAmisFileReadonlySchema(field)
7030
+ }, field.amis, {name: field.name}));
7031
+ }
7032
+ else if(field.type === 'select'){
7033
+ const map = getSelectMap(field.options);
7034
+ columns.push(Object.assign({}, {
7035
+ type: "mapping",
7036
+ name: field.name,
7037
+ label: field.label,
7038
+ map: map,
7039
+ sortable: field.sortable,
7040
+ width: field.width,
7041
+ toggled: field.toggled,
7042
+ className:"whitespace-nowrap",
7043
+ quickEdit: quickEditSchema
7044
+ }, field.amis, {name: field.name}));
7045
+ }
7046
+ else {
7047
+ const tpl = await getFieldTpl(field, options);
7048
+ let type = 'text';
7049
+ if(tpl){
7050
+ type = 'tpl';
7051
+ }else if(field.type === 'html'){
7052
+ type = 'markdown';
7053
+ }else if(field.type === 'url' && field.show_as_qr){
7054
+ type = 'qr-code';
7055
+ }
7056
+ let className = "";
7057
+ if(field.type === 'textarea'){
7058
+ className = 'min-w-56';
7059
+ }
7060
+ if(field.wrap === false){
7061
+ className += " whitespace-nowrap";
7062
+ }
7063
+ if(!field.hidden && !field.extra){
7064
+ columns.push(Object.assign({}, {
7065
+ name: field.name,
7066
+ label: field.label,
7067
+ sortable: field.sortable,
7068
+ // searchable: field.searchable,
7069
+ width: field.width,
7070
+ type: type,
7071
+ tpl: tpl,
7072
+ toggled: field.toggled,
7073
+ className,
7074
+ quickEdit: quickEditSchema,
7075
+ options: field.type === 'html' ? {html: true} : null
7076
+ // toggled: true
7077
+ }, field.amis, {name: field.name}));
7078
+ }
6878
7079
  }
6879
7080
  }
7081
+ // columns.push(getOperation(fields));
7082
+ if(!_$1.some(columns, { name: options.labelFieldName })){
7083
+ const href = Router.getObjectDetailPath({
7084
+ ...options, formFactor: options.formFactor, appId: "${appId}", objectName: options.objectName || "${objectName}", recordId: `\${${options.idFieldName}}`
7085
+ });
7086
+ columns[0].type = "tpl";
7087
+ columns[0].tpl = `<a href="${href}">\${${columns[0].name}}</a>`;
7088
+ }
7089
+ return columns;
6880
7090
  }
6881
7091
 
6882
- /*
6883
- img/avatar字段值添加URL前缀使其在amis中正常显示图片。
6884
- */
6885
- function getScriptForAddUrlPrefixForImgFields(fields){
6886
- let imgFieldsKeys = [];
6887
- let imgFields = {};
6888
- fields.forEach((item)=>{
6889
- if(_$1.includes(['image','avatar'], item.type)){
6890
- imgFieldsKeys.push(item.name);
6891
- imgFields[item.name] = {
6892
- name: item.name,
6893
- type: item.type,
6894
- multiple: item.multiple
6895
- };
6896
- }
6897
- });
6898
- if(!imgFieldsKeys.length){
6899
- return '';
6900
- }
6901
- return `
6902
- // image字段值添加URL前缀
6903
- let imgFieldsKeys = ${JSON.stringify(imgFieldsKeys)};
6904
- let imgFields = ${JSON.stringify(imgFields)};
6905
- imgFieldsKeys.forEach((item)=>{
6906
- let imgFieldValue = data[item];
6907
- let imgFieldDisplayValue = data._display && data._display[item];
6908
- if(imgFieldValue && imgFieldValue.length){
6909
- let fieldProps = imgFields[item];
6910
- if(fieldProps.multiple){
6911
- if(imgFieldDisplayValue instanceof Array){
6912
- data[item] = imgFieldDisplayValue.map((i)=>{ return i.url });
6913
- }
6914
- }else{
6915
- data[item] = imgFieldDisplayValue && imgFieldDisplayValue.url;
6916
- }
6917
- }
6918
- })
6919
- `
6920
- }
7092
+ /**
7093
+ * 生成移动端列表每行显示的amis
7094
+ * @param {*} tpls 要显示的每个字段的tpl
7095
+ * @returns {
7096
+ "type": "wrapper",
7097
+ "body": [{
7098
+ "type": "tpl",
7099
+ "tpl": tpls[index].tpl,
7100
+ "className": "truncate"//左侧样式类
7101
+ },{
7102
+ "type": "tpl",
7103
+ "tpl": tpls[index + 1].tpl,
7104
+ "className": "truncate ml-2 flex flex-shrink-0"//右侧样式类
7105
+ }],
7106
+ "size": "none",
7107
+ "className": "flex items-center justify-between"//每行样式类
7108
+ }
7109
+ */
7110
+ function getMobileLines(tpls){
7111
+ let lines = [];
7112
+ let maxLineCount = 2;
7113
+ let lineChildren = [];
7114
+ let isNewLine = false;
7115
+ let isLeft = true;
7116
+ let lineChildrenClassName = "";
7117
+ let lineClassName = "flex items-center justify-between h-[20px]";
7118
+ tpls.forEach(function(item){
7119
+ if(isNewLine && lines.length < maxLineCount){
7120
+ lines.push({
7121
+ "type": "wrapper",
7122
+ "body": lineChildren,
7123
+ "size": "none",
7124
+ "className": lineClassName
7125
+ });
7126
+ lineChildren = [];
7127
+ }
7128
+ if(isLeft){
7129
+ // 左侧半行
7130
+ lineChildrenClassName = "steedos-listview-item-left truncate";
7131
+ if(item.field.is_wide){
7132
+ // 左侧全行样式可以单独写
7133
+ lineChildrenClassName = "steedos-listview-item-wide truncate";
7134
+ }
7135
+ if(lines.length === 0){
7136
+ // 第一个字段加粗黑色显示
7137
+ lineChildrenClassName += " font-bold text-gray-800";
7138
+ }
7139
+ }
7140
+ else {
7141
+ // 右侧半行
7142
+ lineChildrenClassName = "steedos-listview-item-right truncate ml-2 flex flex-shrink-0";
7143
+ }
7144
+ lineChildren.push({
7145
+ "type": "tpl",
7146
+ "tpl": item.tpl,
7147
+ "className": lineChildrenClassName
7148
+ });
6921
7149
 
6922
- /*
6923
- file字段值重写使其在amis中正常显示附件名、点击附件名下载文件。
6924
- */
6925
- function getScriptForRewriteValueForFileFields(fields){
6926
- let fileFieldsKeys = [];
6927
- let fileFields = {};
6928
- fields.forEach((item)=>{
6929
- if(item.type === 'file'){
6930
- fileFieldsKeys.push(item.name);
6931
- fileFields[item.name] = {
6932
- name: item.name,
6933
- multiple: item.multiple
6934
- };
7150
+ if(item.field.is_wide){
7151
+ // 宽字段占整行
7152
+ isLeft = true;
7153
+ isNewLine = true;
7154
+ }
7155
+ else {
7156
+ isLeft = !isLeft;
7157
+ isNewLine = isLeft;
6935
7158
  }
6936
7159
  });
6937
- if(!fileFieldsKeys.length){
6938
- return '';
7160
+
7161
+ if(lineChildren.length && lines.length < maxLineCount){
7162
+ lines.push({
7163
+ "type": "wrapper",
7164
+ "body": lineChildren,
7165
+ "size": "none",
7166
+ "className": lineClassName
7167
+ });
6939
7168
  }
6940
- return `
6941
- // file字段值重写以便编辑时正常显示附件名、点击附件名正常下载附件
6942
- let fileFieldsKeys = ${JSON.stringify(fileFieldsKeys)};
6943
- let fileFields = ${JSON.stringify(fileFields)};
6944
- fileFieldsKeys.forEach((item)=>{
6945
- let fileFieldValue = data[item];
6946
- let fileFieldDisplayValue = data._display && data._display[item];
6947
- if(fileFieldValue && fileFieldValue.length){
6948
- if(fileFields[item].multiple){
6949
- if(fileFieldDisplayValue instanceof Array){
6950
- data[item] = fileFieldDisplayValue.map((item, index)=>{
6951
- return {
6952
- value: fileFieldValue[index],
6953
- name: item.name,
6954
- url: item.url + "?download=true",
6955
- state: "uploaded"
6956
- }
6957
- });
6958
- }
6959
- }else{
6960
- data[item] = [{
6961
- value: fileFieldValue,
6962
- name: fileFieldDisplayValue.name,
6963
- url: fileFieldDisplayValue.url + "?download=true",
6964
- state: "uploaded"
6965
- }];
6966
- }
6967
- }
6968
- })
6969
- `
7169
+
7170
+ return lines;
6970
7171
  }
6971
7172
 
6972
- async function getEditFormInitApi(object, recordId, fields, options){
6973
- const data = await getFindOneQuery$1(object, recordId, fields);
6974
- data.recordId = "${recordId}";
6975
- data.objectName = "${objectName}";
6976
- data.uiSchema = "${uiSchema}";
6977
- data.global = "${global}";
6978
- data.context = "${context}";
6979
- data.defaultData = "${defaultData}";
6980
- data._master = "${_master}";
6981
-
6982
- return {
6983
- method: "post",
6984
- url: getApi$2() + '&objectName=${objectName}' ,
6985
- // sendOn: "!!this.recordId",
6986
- cache: API_CACHE,
6987
- requestAdaptor: `
6988
- // 所有不想在network请求中发送的数据都应该从data中分离出来,data变量只需要留下query才需要发送出去
6989
- var { recordId, objectName, uiSchema, global, context, ...data} = api.data;
6990
- if(!recordId){
6991
- // 新建则不请求任何数据
6992
- data.query = "{data:" + objectName + "(filters: " + JSON.stringify(["_id", "=", null]) + ", top: 1){_id}}";
7173
+ async function getMobileTableColumns(fields, options){
7174
+ const columns = [];
7175
+ let nameField = {};
7176
+ let tpls = [];
7177
+ for (const field of fields) {
7178
+ let tpl = "";
7179
+ if(field.is_name || field.name === options.labelFieldName){
7180
+ nameField = field;
7181
+ options.onlyDisplayLabel = true;
7182
+ tpl = await getFieldTpl(field, options);
7183
+ }
7184
+ else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7185
+ // 图片和附件类型字段暂时显示为附件名称,后续需要再优化
7186
+ tpl = `\${_display.${field.name}.name}`;
7187
+ }
7188
+ else {
7189
+ if(field.type === 'lookup' || field.type === 'master_detail'){
7190
+ options.onlyDisplayLabel = true;
6993
7191
  }
6994
- api.data = data;
6995
- ${options.initApiRequestAdaptor || ''}
6996
- return api;
6997
- `,
6998
- adaptor: `
6999
- const recordId = api.body.recordId;
7000
- let initialValues={};
7001
- if(recordId && payload.data.data){
7002
- var data = payload.data.data[0];
7003
- const dataKeys = _.keys(data);
7004
- const uiSchema = api.body.uiSchema;
7005
- const fieldKeys = uiSchema && _.keys(uiSchema.fields);
7192
+ tpl = await getFieldTpl(field, options);
7193
+ }
7194
+ if(!tpl){
7195
+ tpl = `\${${field.name}}`;
7196
+ }
7197
+ if(!field.hidden && !field.extra){
7198
+ tpls.push({ field, tpl });
7199
+ }
7200
+ }
7201
+ const url = getNameTplUrl(nameField, options);
7006
7202
 
7007
- if(data){
7008
- ${getScriptForAddUrlPrefixForImgFields(fields)}
7009
- ${getScriptForRewriteValueForFileFields(fields)}
7203
+ const columnLines = getMobileLines(tpls);
7010
7204
 
7011
- _.each(dataKeys, function(key){
7012
- if(fieldKeys.indexOf(key)<0){
7013
- delete data[key];
7014
- }
7015
- })
7016
-
7017
- //初始化接口返回的字段移除字段值为null的字段
7018
- for (key in data){
7019
- if(data[key] === null){
7020
- delete data[key];
7021
- }
7205
+
7206
+ let column = {
7207
+ name: nameField.name,
7208
+ label: nameField.label,
7209
+ sortable: nameField.sortable,
7210
+ type: "button",
7211
+ level: "link",
7212
+ actionType: "link",
7213
+ link: url,
7214
+ innerClassName: "steedos-listview-item block text-gray-500",
7215
+ body: {
7216
+ "type": "wrapper",
7217
+ "body": columnLines,
7218
+ "size": "none",
7219
+ "className": "p-1"
7220
+ }
7221
+ };
7222
+
7223
+ if(options.objectName === 'cms_files'){
7224
+ if(window.Meteor?.isCordova){
7225
+ column = {
7226
+ ...column,
7227
+ actionType: "",
7228
+ link: "",
7229
+ onEvent: {
7230
+ "click": {
7231
+ "actions": [
7232
+ {
7233
+ "script": `
7234
+ let cms_url = "/api/files/files/"+event.data.versions[0]+"?download=true"
7235
+ Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
7236
+ `,
7237
+ "actionType": "custom"
7238
+ }
7239
+ ],
7240
+ "weight": 0
7022
7241
  }
7023
- };
7024
- initialValues = data;
7025
- }
7026
- else{
7027
- var uiSchema = api.body.uiSchema;
7028
- var defaultData = api.body.defaultData;
7029
- var defaultValues = {};
7030
- _.each(uiSchema?.fields, function(field){
7031
- var value = SteedosUI.getFieldDefaultValue(field, api.body.global);
7032
- if(value){
7033
- defaultValues[field.name] = value;
7034
- }
7035
- });
7036
- if(defaultData && _.isObject(defaultData) && !_.isArray(defaultData)){
7037
- defaultValues = Object.assign({}, defaultValues, defaultData)
7038
7242
  }
7039
- if(uiSchema.form){
7040
- try{
7041
- var objectFormConfig = JSON.parse(uiSchema.form);
7042
- var formInitialValuesFun = objectFormConfig.initialValues;
7043
- if(formInitialValuesFun){
7044
- formInitialValuesFun = new Function("return " + formInitialValuesFun)();
7045
- }
7046
- if(typeof formInitialValuesFun === "function"){
7047
- initialValues = formInitialValuesFun.apply({doc: defaultValues || {} , global: api.body.global, master: api.body._master })
7048
- }
7049
- }
7050
- catch(ex){
7051
- console.warn(ex);
7243
+ };
7244
+ }else {
7245
+ column = {
7246
+ ...column,
7247
+ actionType: "",
7248
+ link: "",
7249
+ onEvent: {
7250
+ "click": {
7251
+ "actions": [
7252
+ {
7253
+ "args": {
7254
+ "api": {
7255
+ "url": url,
7256
+ "method": "get",
7257
+ "headers": {
7258
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
7259
+ }
7260
+ }
7261
+ },
7262
+ "actionType": "download"
7263
+ }
7264
+ ],
7265
+ "weight": 0
7052
7266
  }
7053
7267
  }
7054
- if(_.isObject(initialValues)){
7055
- // uiSchema.form.initialValues为函数且执行后为json,则优先取initialValues中的默认值
7056
- initialValues = Object.assign({}, defaultValues, initialValues);
7057
- }
7058
- else{
7059
- initialValues = defaultValues;
7060
- }
7061
- }
7062
- // data下的变量需要在保存接口(getSaveApi)中被删除。
7063
- payload.data = {
7064
- ...initialValues
7065
- }
7066
- ${options.initApiAdaptor || ''}
7067
- return payload;
7068
- `,
7069
- responseData: {
7070
- initialValues: "$$",
7071
- editFormInited: true
7072
- },
7073
- data: data,
7074
- headers: {
7075
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7268
+ };
7076
7269
  }
7270
+
7077
7271
  }
7078
- }
7079
7272
 
7273
+ columns.push(column);
7274
+
7080
7275
 
7081
- function getSaveApi(object, recordId, fields, options){
7082
- return {
7083
- method: 'post',
7084
- url: getApi$2(),
7085
- data: getSaveQuery(object, recordId),
7086
- requestAdaptor: getSaveRequestAdaptor(fields, options),
7087
- responseData: {
7088
- "recordId": "${record._id}"
7089
- },
7090
- adaptor: `
7091
- if(payload.errors){
7092
- payload.status = 2;
7093
- payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
7094
- }
7095
- ${options.apiAdaptor || ''}
7096
- return payload;
7097
- `,
7098
- headers: {
7099
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7100
- }
7101
- }
7276
+ return columns;
7102
7277
  }
7103
7278
 
7104
- function getBatchDelete(objectName){
7279
+ function getDefaultParams(options){
7105
7280
  return {
7106
- method: 'post',
7107
- url: getApi$2(),
7108
- requestAdaptor: `
7109
- var ids = api.data.ids.split(",");
7110
- var deleteArray = [];
7111
- ids.forEach((id,index)=>{
7112
- deleteArray.push(\`delete__\${index}:${objectName}__delete(id: "\${id}")\`);
7113
- })
7114
- api.data = {query: \`mutation{\${deleteArray.join(',')}}\`};
7115
- return api;
7116
- `,
7117
- data: {
7118
- ids: `\${ids}`
7119
- },
7120
- headers: {
7121
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
7122
- }
7281
+ perPage: options.top || options.perPage || config.listView.perPage
7123
7282
  }
7124
7283
  }
7125
7284
 
7126
- /*
7127
- * @Author: baozhoutao@steedos.com
7128
- * @Date: 2022-05-26 16:02:08
7129
- * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
7130
- * @LastEditTime: 2023-06-02 16:54:41
7131
- * @Description:
7132
- */
7285
+ function getButtonVisibleOn(button){
7286
+ let visible= button.visible;
7133
7287
 
7134
- const getFieldSchemaArray = (formFields) => {
7135
- let fieldSchemaArray = [];
7136
- fieldSchemaArray.length = 0;
7288
+ if(button._visible){
7289
+ visible = button._visible;
7290
+ }
7137
7291
 
7138
- _$1.forEach(formFields, (field) => {
7139
- if (!field.group || field.group == 'null' || field.group == '-')
7140
- field.group = '通用';
7141
- const fieldName = field.name;
7142
- let isObjectField = /\w+\.\w+/.test(fieldName);
7143
- if (field.type == 'grid' || field.type == 'object') {
7144
- // field.group = field.label
7145
- field.is_wide = true;
7292
+ if(isBoolean(visible)){
7293
+ visible = visible.toString();
7146
7294
  }
7147
7295
 
7148
- if (!isObjectField) {
7149
- if (!field.hidden) {
7150
- fieldSchemaArray.push(Object.assign({ name: fieldName }, field, { permission: { allowEdit: true } }));
7151
- }
7296
+ if(visible){
7297
+ // if(visible.indexOf("Meteor.") > 0 || visible.indexOf("Creator.") > 0 || visible.indexOf("Session.") > 0){
7298
+ // console.warn('无效的visible', visible)
7299
+ // return 'false';
7300
+ // }
7301
+ if(visible.trim().startsWith('function')){
7302
+ return `${visible}(objectName, typeof _id === 'undefined' ? null: _id, typeof record === 'undefined' ? (typeof recordPermissions === 'undefined' ? {} : recordPermissions) : record.recordPermissions, data)`
7303
+ }
7304
+ return visible;
7152
7305
  }
7153
- });
7154
- return fieldSchemaArray;
7155
- };
7156
7306
 
7157
- const getSection = async (formFields, permissionFields, fieldSchemaArray, sectionName, ctx) => {
7158
- if (!ctx) {
7159
- ctx = {};
7160
- }
7161
- const sectionFields = _$1.filter(fieldSchemaArray, { 'group': sectionName });
7162
- if (sectionFields.length == _$1.filter(sectionFields, ['hidden', true]).length) {
7163
- return;
7164
- }
7307
+ if(button.type === 'amis_button'){
7308
+ const amisSchema = button.amis_schema;
7309
+ if(amisSchema && amisSchema.body && amisSchema.body.length > 0){
7310
+ const btn1 = amisSchema.body[0];
7311
+ return btn1.visibleOn
7312
+ }
7313
+ }
7314
+ }
7165
7315
 
7166
- const fieldSetBody = [];
7316
+ async function getTableOperation(ctx){
7317
+ const buttons = ctx.buttons;
7318
+ const operationButtons = [];
7319
+ each(buttons, (button)=>{
7320
+ if(isBoolean(button.visible)){
7321
+ button.visible = button.visible.toString();
7322
+ }
7323
+ // operationButtons.push({
7324
+ // type: 'button',
7325
+ // label: button.label,
7326
+ // visibleOn: button.visible ? `${button.visible}` : (button._visible ? `${button._visible}` : null),
7327
+ // onEvent: {
7328
+ // click: {
7329
+ // actions: []
7330
+ // }
7331
+ // }
7332
+ // })
7167
7333
 
7168
- for (const perField of sectionFields) {
7169
- let field = perField;
7170
- if (perField.type === 'grid') {
7171
- field = await getGridFieldSubFields(perField, formFields);
7172
- // console.log(`perField.type grid ===> field`, field)
7173
- } else if (perField.type === 'object') {
7174
- field = await getObjectFieldSubFields(perField, formFields);
7175
- // console.log(`perField.type object ===> field`, field)
7334
+ operationButtons.push({
7335
+ type: 'steedos-object-button',
7336
+ name: button.name,
7337
+ objectName: button.objectName,
7338
+ visibleOn: getButtonVisibleOn(button),
7339
+ className: 'antd-Button--default'
7340
+ });
7341
+ });
7342
+ if(operationButtons.length < 1){
7343
+ return ;
7176
7344
  }
7177
- if (field.name.indexOf(".") < 0) {
7178
- ctx.__formFields = formFields;
7179
- const amisField = await convertSFieldToAmisField(field, field.readonly, ctx);
7180
- // console.log(`${field.name} amisField`, field, amisField)
7181
- if (amisField) {
7182
- fieldSetBody.push(amisField);
7183
- }
7345
+ return {
7346
+ type: 'operation',
7347
+ label: '操作',
7348
+ fixed: 'right',
7349
+ labelClassName: 'text-center',
7350
+ className: 'text-center steedos-listview-operation w-20',
7351
+ buttons: [
7352
+ {
7353
+ "type": "steedos-dropdown-button",
7354
+ "label": "xxx",
7355
+ "buttons": operationButtons,
7356
+ "placement": "bottomRight",
7357
+ "overlayClassName": "shadow !min-w-[160px]",
7358
+ "trigger": ["click"],
7359
+ "id": "u:c2140a365019",
7360
+ onOpenApi: {
7361
+ url: `\${context.rootUrl}/service/api/@\${objectName}/recordPermissions/\${_id}`,
7362
+ method: "get",
7363
+ data: {
7364
+ $: "$$",
7365
+ objectName: "${objectName}",
7366
+ listViewId: "${listViewId}",
7367
+ appId: "${appId}",
7368
+ formFactor: "${formFactor}",
7369
+ context: `\${context}`
7370
+ },
7371
+ headers: {
7372
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7373
+ },
7374
+ adaptor: `
7375
+ payload = {
7376
+ record: {
7377
+ recordPermissions: payload
7378
+ }
7379
+ };
7380
+ return payload;
7381
+ `,
7382
+ }
7383
+ }
7384
+ ]
7184
7385
  }
7185
- }
7386
+ }
7186
7387
 
7187
- // fieldSet 已支持显隐控制
7188
- const sectionFieldsVisibleOn = _$1.map(_$1.compact(_$1.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
7189
- return visibleOn;
7190
- });
7191
-
7192
- let section = {
7193
- "type": "fieldSet",
7194
- "title": sectionName,
7195
- "collapsable": true,
7196
- "body": fieldSetBody,
7197
- };
7198
-
7199
- if (ctx.enableTabs) {
7200
- section = {
7201
- "title": sectionName,
7202
- "body": fieldSetBody,
7203
- };
7204
- }
7205
-
7206
- if (sectionFieldsVisibleOn.length > 0 && fieldSetBody.length === sectionFieldsVisibleOn.length) {
7207
- section.visibleOn = `${sectionFieldsVisibleOn.join(" || ")}`;
7208
- }
7209
- return section
7210
- };
7211
-
7212
- const getSections = async (permissionFields, formFields, ctx) => {
7213
- if (!ctx) {
7214
- ctx = {};
7215
- }
7216
- const fieldSchemaArray = getFieldSchemaArray(formFields);
7217
- const _sections = _$1.groupBy(fieldSchemaArray, 'group');
7218
- const sections = [];
7219
- var sectionVisibleOns = [];
7220
- for (const key in _sections) {
7221
- const section = await getSection(formFields, permissionFields, fieldSchemaArray, key, ctx);
7222
- if (section.body.length > 0) {
7223
- if (section.visibleOn) {
7224
- sectionVisibleOns.push(section.visibleOn);
7225
- }
7226
- else {
7227
- sectionVisibleOns.push("true");
7228
- }
7229
- sections.push(section);
7388
+ async function getTableSchema$1(fields, options){
7389
+ if(!options){
7390
+ options = {};
7230
7391
  }
7231
- }
7232
- /*
7233
- 为了实现只有一个分组时隐藏该分组标题,需要分三种情况(分组如果没有visibleon属性就代表一定显示,有visibleon需要进行判断)
7234
- 1 当前分组为隐藏时,标题就设置为隐藏
7235
- 2 当前分组为显示时,其他分组只要有一个是显示,就显示该分组标题
7236
- 3 当前分组为显示时,其他分组都隐藏,就隐藏该分组标题
7237
- */
7238
- sections.forEach((section, index) => {
7239
- var tempSectionVisibleOns = sectionVisibleOns.slice();
7240
- tempSectionVisibleOns.splice(index, 1);
7241
- section.headingClassName = {
7242
- "hidden": `!((${tempSectionVisibleOns.join(" || ") || 'false'}) && ${sectionVisibleOns[index]})`
7243
- };
7244
- });
7392
+ let columns = [];
7393
+ if(options.formFactor === 'SMALL' || ["split"].indexOf(options.displayAs) > -1){
7394
+ columns = await getMobileTableColumns(fields, options);
7395
+ }
7396
+ else {
7397
+ columns = await getTableColumns(fields, options);
7398
+ columns.push(await getTableOperation(options));
7399
+ }
7400
+ return {
7401
+ mode: "table",
7402
+ name: "thelist",
7403
+ headerToolbarClassName: "py-2 px-2 border-gray-300 bg-gray-100 border-solid border-b",
7404
+ className: "",
7405
+ draggable: false,
7406
+ defaultParams: getDefaultParams(options),
7407
+ columns: columns,
7408
+ syncLocation: false,
7409
+ keepItemSelectionOnPageChange: true,
7410
+ checkOnItemClick: false,
7411
+ labelTpl: `\${${options.labelFieldName}}`,
7412
+ autoFillHeight: false, // 自动高度效果不理想,先关闭
7413
+ columnsTogglable: false,
7414
+ }
7415
+ }
7245
7416
 
7246
- if (ctx.enableTabs) {
7247
- return [
7248
- {
7249
- "type": "tabs",
7250
- "tabs": sections,
7251
- "tabsMode": ctx.tabsMode
7252
- }
7253
- ]
7254
- }
7255
7417
 
7256
- return sections;
7257
- };
7258
7418
 
7259
- /*
7260
- * @Author: baozhoutao@steedos.com
7261
- * @Date: 2022-07-07 11:02:29
7262
- * @LastEditors: baozhoutao@steedos.com
7263
- * @LastEditTime: 2023-03-07 17:19:34
7264
- * @Description:
7419
+ /**
7420
+ *
7421
+ * @param {*} mainObject
7422
+ * @param {*} fields
7423
+ * @param {*} options = {filter: listview 过滤条件, ...}
7424
+ * @returns
7265
7425
  */
7426
+ async function getTableApi(mainObject, fields, options){
7427
+ const searchableFields = [];
7428
+ let { filter, filtersFunction, sort, top, setDataToComponentId = '' } = options;
7266
7429
 
7267
- async function getFormBody(permissionFields, formFields, ctx){
7268
- return await getSections(permissionFields, formFields, ctx);
7269
- }
7270
-
7271
- // lodash的defaultsDeep函数有bug,无法正确合并值为数值的节点,重写修正该函数
7272
- // 源码出处:https://github.com/nodeutils/defaults-deep
7273
- const defaultsDeep = (...args)=>{
7274
- let output = {};
7275
- toArray(args).reverse().forEach(item=> {
7276
- mergeWith(output, item, (objectValue, sourceValue) => {
7277
- return isArray(sourceValue) ? sourceValue : undefined;
7430
+ if(_$1.isArray(filter)){
7431
+ filter = _$1.map(filter, function(item){
7432
+ if(item.operation){
7433
+ return [item.field, item.operation, item.value];
7434
+ }else {
7435
+ return item
7436
+ }
7278
7437
  });
7279
- });
7280
- return output;
7281
- };
7282
-
7283
- function getBulkActions(objectSchema){
7284
- return [
7285
- {
7286
- "type": "button",
7287
- "level": "danger",
7288
- "label": "批量删除",
7289
- "actionType": "ajax",
7290
- "confirmText": "确定要删除吗",
7291
- "className": "hidden",
7292
- "id": "batchDelete",
7293
- "api": getBatchDelete(objectSchema.name),
7294
- }
7295
- // {
7296
- // "label": "批量修改",
7297
- // "actionType": "dialog",
7298
- // "dialog": {
7299
- // "title": "批量编辑",
7300
- // "name": "sample-bulk-edit",
7301
- // "body": {
7302
- // "type": "form",
7303
- // "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample/bulkUpdate2",
7304
- // "controls": [
7305
- // {
7306
- // "type": "hidden",
7307
- // "name": "ids"
7308
- // },
7309
- // {
7310
- // "type": "text",
7311
- // "name": "name",
7312
- // "label": "Name"
7313
- // }
7314
- // ]
7315
- // }
7316
- // }
7317
- // }
7318
- ]
7319
- }
7320
-
7321
- async function getObjectCRUD(objectSchema, fields, options){
7322
- // console.time('getObjectCRUD');
7323
- const { top, perPage, showDisplayAs = false, displayAs, crudClassName = "" } = options;
7324
- const nonpaged = objectSchema.paging && objectSchema.paging.enabled === false;
7325
- const isTreeObject = objectSchema.enable_tree;
7326
- const bulkActions = getBulkActions(objectSchema);
7327
- const bodyProps = {
7328
- // toolbar: getToolbar(),
7329
- // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
7330
- headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
7331
- footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
7332
- disableStatistics: options.queryCount === false
7333
- }),
7334
- filter: options.filterVisible !== false && await getObjectFilter(objectSchema, fields, options),
7335
- };
7336
- if(options.formFactor !== 'SMALL' || ["split"].indexOf(options.displayAs) == -1){
7337
- Object.assign(bodyProps, {
7338
- bulkActions: options.bulkActions != false ? bulkActions : false
7339
- });
7340
7438
  }
7341
- // yml里配置的 不分页和enable_tree:true 优先级最高,组件中输入的top次之。
7342
- options.queryCount = true;
7343
- if(nonpaged || isTreeObject){
7344
- options.top = 50000;
7345
- bodyProps.footerToolbar = [];
7346
- options.queryCount = true; // 禁止翻页的时候, 需要查找总数
7347
- }else if(top){
7348
- bodyProps.footerToolbar = [];
7349
- if(options.isRelated){
7350
- options.queryCount = true;
7351
- }else {
7352
- options.queryCount = false;
7353
- }
7439
+ if(!filter){
7440
+ filter = [];
7354
7441
  }
7355
- // console.log(`getObjectHeaderToolbar====2===>`, options.filterVisible)
7356
- bodyProps.headerToolbar = getObjectHeaderToolbar(objectSchema, options.formFactor, {
7357
- showDisplayAs,
7358
- hiddenCount: options.queryCount === false,
7359
- headerToolbarItems: options.headerToolbarItems,
7360
- filterVisible: options.filterVisible
7442
+ let baseFilters = null;
7443
+ if(filter){
7444
+ baseFilters = filter;
7445
+ }
7446
+ _$1.each(fields,function(field){
7447
+ if(field.searchable){
7448
+ searchableFields.push(field.name);
7449
+ }
7361
7450
  });
7362
7451
 
7452
+ const fileFields = {};
7453
+ const fileFieldsKeys = [];
7454
+ // 含有optionsFunction属性, 无reference_to属性的lookup字段
7455
+ const lookupFields = {};
7456
+ fields.forEach((item)=>{
7457
+ if(_$1.includes(['image','avatar','file'], item.type)){
7458
+ fileFieldsKeys.push(item.name);
7459
+ fileFields[item.name] = {
7460
+ name: item.name,
7461
+ type: item.type,
7462
+ multiple: item.multiple
7463
+ };
7464
+ }
7465
+ if(_$1.includes(['lookup'], item.type) && !item.reference_to ){
7466
+ lookupFields[item.name] = item;
7467
+ }
7468
+ });
7363
7469
 
7364
- let body = null;
7365
- const id = `listview_${objectSchema.name}`;
7366
- if(options.formFactor === 'SMALL' && false){
7367
- delete bodyProps.bulkActions;
7368
- delete bodyProps.headerToolbar;
7369
- delete bodyProps.footerToolbar;
7370
- const card = await getCardSchema(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: objectSchema.NAME_FIELD_KEY || 'name'}, options, {actions: false}));
7371
- body = Object.assign({}, card , {
7372
- type: 'crud',
7373
- primaryField: '_id',
7374
- id: id,
7375
- name: id,
7376
- keepItemSelectionOnPageChange: false,
7377
- api: await getTableApi(objectSchema, fields, options),
7378
- hiddenOn: options.tableHiddenOn,
7379
- },
7380
- bodyProps
7381
- );
7382
- }else {
7383
- let labelFieldName = objectSchema.NAME_FIELD_KEY || 'name';
7384
- // organizations 对象的历史遗留问题, fullname 被标记为了 名称字段. 在此处特殊处理.
7385
- if(objectSchema.name === 'organizations'){
7386
- labelFieldName = 'name';
7387
- }
7388
- const table = await getTableSchema$1(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: labelFieldName}, options));
7389
- delete table.mode;
7390
-
7391
- body = Object.assign({}, table, {
7392
- type: 'crud',
7393
- primaryField: '_id',
7394
- affixHeader: false,
7395
- id: id,
7396
- name: id,
7397
- keepItemSelectionOnPageChange: true,
7398
- api: await getTableApi(objectSchema, fields, options),
7399
- hiddenOn: options.tableHiddenOn,
7400
- autoFillHeight: options.isRelated ? false : true,
7401
- className: `flex-auto ${crudClassName || ""}`,
7402
- bodyClassName: "bg-white",
7403
- crudClassName: crudClassName,
7404
- },
7405
- bodyProps,
7406
- );
7470
+ let valueField = mainObject.key_field || '_id';
7471
+ const api = await getApi(mainObject, null, fields, {count: options.queryCount, alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"`});
7472
+
7473
+ if(options.isRelated){
7474
+ api.url += "&recordId=${_master.recordId}";
7407
7475
  }
7408
7476
 
7409
- const defaults = options.defaults;
7410
- if (defaults) {
7411
- const listSchema = defaults.listSchema || {};
7412
- body = defaultsDeep({}, listSchema, body);
7413
- const headerSchema = defaults.headerSchema;
7414
- const footerSchema = defaults.footerSchema;
7415
- if (headerSchema || footerSchema) {
7416
- let wrappedBody = [body];
7417
- if (headerSchema) {
7418
- if(___default.isArray(headerSchema)){
7419
- wrappedBody = ___default.union(headerSchema,wrappedBody);
7420
- }
7421
- else {
7422
- wrappedBody.unshift(headerSchema);
7423
- }
7477
+ api.data.$term = "$term";
7478
+ api.data.term = "$term";
7479
+ api.data.$self = "$$";
7480
+ api.data.self = "$$";
7481
+ api.data.filter = "$filter";
7482
+ api.data.loaded = "${loaded}";
7483
+ api.data.listViewId = "${listViewId}";
7484
+ api.data.listName = "${listName}";
7485
+ api.requestAdaptor = `
7486
+ // selfData 中的数据由 CRUD 控制. selfData中,只能获取到 CRUD 给定的data. 无法从数据链中获取数据.
7487
+ let selfData = JSON.parse(JSON.stringify(api.data.$self));
7488
+ // 保留一份初始data,以供自定义发送适配器中获取原始数据。
7489
+ const data = _.cloneDeep(api.data);
7490
+ try{
7491
+ // TODO: 不应该直接在这里取localStorage,应该从外面传入
7492
+ const listViewId = api.data.listViewId;
7493
+ const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
7494
+ let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
7495
+ if(localListViewProps){
7496
+ localListViewProps = JSON.parse(localListViewProps);
7497
+ selfData = Object.assign({}, localListViewProps, selfData);
7498
+ if(!api.data.filter){
7499
+ api.data.filter = localListViewProps.filter;
7500
+ }
7501
+ if(!api.data.loaded){
7502
+ // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
7503
+ // 所以会把localSearchableFilter中已经存过的页码覆盖
7504
+ // 如果是第一次加载组件始终让翻页页码从本地存储中取值
7505
+ let formFactor = "${options.formFactor}";
7506
+ // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
7507
+ api.data.pageNo = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
7508
+ }
7509
+ }
7424
7510
  }
7425
- if (footerSchema) {
7426
- if(___default.isArray(footerSchema)){
7427
- wrappedBody = ___default.union(wrappedBody,footerSchema);
7428
- }
7429
- else {
7430
- wrappedBody.push(footerSchema);
7431
- }
7511
+ catch(ex){
7512
+ console.error("本地存储中crud参数解析异常:", ex);
7432
7513
  }
7433
- body = wrappedBody;
7434
- }
7435
- }
7436
- // console.timeEnd('getObjectCRUD');
7437
- // TODO: data应该只留loaded,其他属性都改为从上层传递下来
7438
- return {
7439
- type: 'service',
7440
- className: '',
7441
- id: `service_${id}`,
7442
- name: `page`,
7443
- data: {
7444
- objectName: objectSchema.name,
7445
- // _id: null,
7446
- recordPermissions: objectSchema.permissions,
7447
- uiSchema: objectSchema,
7448
- // loaded: false //crud接收适配器中设置为true,否则就是刷新浏览器第一次加载
7449
- },
7450
- body: body
7451
- }
7452
- }
7514
+ ${baseFilters ? `var systemFilters = ${JSON.stringify(baseFilters)};` : 'var systemFilters = [];'}
7515
+ var _ids = []
7516
+ const filtersFunction = ${filtersFunction};
7517
+ if(filtersFunction){
7518
+ const _filters = filtersFunction(systemFilters, api.data.$self);
7519
+ if(api.data.listName == "recent"){
7520
+ _ids = _filters[2]
7521
+ }
7522
+ if(_filters && _filters.length > 0){
7523
+ if(_.isEmpty(systemFilters)){
7524
+ systemFilters = _filters || [];
7525
+ }else{
7526
+ systemFilters = [systemFilters, 'and', _filters];
7527
+ }
7528
+ }
7529
+ }
7530
+ let userFilters =[];
7531
+
7532
+ if(_.isEmpty(systemFilters)){
7533
+ systemFilters = api.data.filter || [];
7534
+ }else{
7535
+ if(!_.isEmpty(api.data.filter)){
7536
+ systemFilters = [systemFilters, 'and', api.data.filter];
7537
+ }
7538
+ }
7539
+ var pageSize = api.data.pageSize || 10;
7540
+ var pageNo = api.data.pageNo || 1;
7541
+ var skip = (pageNo - 1) * pageSize;
7542
+ var orderBy = api.data.orderBy || '';
7543
+ var orderDir = api.data.orderDir || '';
7544
+ var sort = orderBy + ' ' + orderDir;
7545
+ sort = orderBy ? sort : "${sort || ''}";
7546
+ var allowSearchFields = ${JSON.stringify(searchableFields)};
7547
+ if(api.data.$term){
7548
+ userFilters = [["name", "contains", "'+ api.data.$term +'"]];
7549
+ }else if(selfData.op === 'loadOptions' && selfData.value){
7550
+ userFilters = [["${valueField.name}", "=", selfData.value]];
7551
+ }
7552
+
7553
+ var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
7453
7554
 
7454
- const getGlobalData = (mode)=>{
7455
- const user = getSteedosAuth();
7456
- return {mode: mode, user: user, spaceId: user.spaceId, userId: user.userId}
7457
- };
7555
+ if(searchableFilter.length > 0){
7556
+ if(userFilters.length > 0 ){
7557
+ userFilters = [userFilters, 'and', searchableFilter];
7558
+ }else{
7559
+ userFilters = searchableFilter;
7560
+ }
7561
+ }
7458
7562
 
7459
- const getFormFields = (objectSchema, formProps)=>{
7460
- /**
7461
- * fieldsExtend: 重写字段定义
7462
- * fields: 包含的字段
7463
- * excludedFields: 排除的字段
7464
- */
7465
- const { fieldsExtend, fields: includedFields, excludedFields } = formProps;
7466
-
7467
- let fields = {};
7468
- // 以uiSchema fields 为基础, 遍历字段, 并更新字段定义
7469
- ___default.forEach(objectSchema.fields, (field, fieldName)=>{
7470
- if(!lodash.has(field, "name")){
7471
- field.name = fieldName;
7472
- }
7473
- if(fieldsExtend && fieldsExtend[fieldName]){
7474
- fields[field.name] = Object.assign({}, field, fieldsExtend[fieldName], {name: field.name});
7475
- }else {
7476
- fields[field.name] = field;
7477
- }
7478
- });
7563
+ if(allowSearchFields){
7564
+ allowSearchFields.forEach(function(key){
7565
+ const keyValue = selfData[key];
7566
+ if(_.isString(keyValue)){
7567
+ userFilters.push([key, "contains", keyValue]);
7568
+ }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
7569
+ userFilters.push([key, "=", keyValue]);
7570
+ }
7571
+ })
7572
+ }
7479
7573
 
7480
- if(!___default.isEmpty(includedFields) && ___default.isArray(includedFields)){
7481
- const includedFieldsMap = {};
7482
- ___default.each(includedFields, (fName, index)=>{
7483
- if(fields[fName]){
7484
- includedFieldsMap[fName] = Object.assign({}, fields[fName], {sort_no: index});
7485
- }
7486
- });
7487
- fields = includedFieldsMap;
7488
- }
7574
+ if(selfData.__keywords && allowSearchFields){
7575
+ const keywordsFilters = [];
7576
+ allowSearchFields.forEach(function(key, index){
7577
+ const keyValue = selfData.__keywords;
7578
+ if(keyValue){
7579
+ keywordsFilters.push([key, "contains", keyValue]);
7580
+ if(index < allowSearchFields.length - 1){
7581
+ keywordsFilters.push('or');
7582
+ }
7583
+ }
7584
+ })
7585
+ userFilters.push(keywordsFilters);
7586
+ };
7489
7587
 
7490
- if(!___default.isEmpty(excludedFields) && ___default.isArray(excludedFields)){
7491
- ___default.each(excludedFields, (fName)=>{
7492
- delete fields[fName];
7493
- });
7494
- }
7588
+ let filters = [];
7495
7589
 
7496
- return lodash.sortBy(___default.values(fields), "sort_no");
7497
- };
7590
+ if(!_.isEmpty(systemFilters)){
7591
+ filters = systemFilters;
7592
+ };
7593
+ if(api.data.$self.additionalFilters){
7594
+ if(_.isString(api.data.$self.additionalFilters)){
7595
+ userFilters.push(eval(api.data.$self.additionalFilters))
7596
+ }else{
7597
+ userFilters.push(api.data.$self.additionalFilters)
7598
+ }
7599
+ }
7498
7600
 
7499
- async function getObjectForm(objectSchema, ctx){
7500
- const { recordId, formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, tabId, appId, defaults } = ctx;
7501
- const fields = ___default.values(objectSchema.fields);
7502
- const formFields = getFormFields(objectSchema, ctx);
7503
- const formSchema = defaults && defaults.formSchema || {};
7504
- if(___default.has(formSchema, 'className')){
7505
- formSchema.className = 'steedos-amis-form';
7506
- }
7507
- const amisSchema = {
7508
- type: 'service',
7509
- className: 'p-0',
7510
- name: `page_edit_${recordId}`,
7511
- api: await getEditFormInitApi(objectSchema, recordId, fields, ctx),
7512
- data:{
7513
- editFormInited: false
7514
- },
7515
- // data: {global: getGlobalData('edit'), recordId: recordId, objectName: objectSchema.name, context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
7516
- initApi: null,
7517
- initFetch: null ,
7518
- body: [defaultsDeep({}, formSchema, {
7519
- type: "form",
7520
- mode: layout,
7521
- data: {
7522
- "&": "${initialValues}"
7523
- },
7524
- labelAlign,
7525
- persistData: false,
7526
- resetAfterSubmit: true,
7527
- preventEnterSubmit: true,
7528
- promptPageLeave: true,
7529
- canAccessSuperData: false,
7530
- name: `form_edit_${recordId}`,
7531
- debug: false,
7532
- title: "",
7533
- submitText: "", // amis 表单不显示提交按钮, 表单提交由项目代码接管
7534
- api: await getSaveApi(objectSchema, recordId, fields, ctx),
7535
- initFetch: recordId != 'new',
7536
- body: await getFormBody(fields, formFields, ctx),
7537
- panelClassName:'m-0 sm:rounded-lg shadow-none border-none',
7538
- bodyClassName: 'p-0',
7539
- className: 'steedos-amis-form',
7540
- hiddenOn: "${editFormInited != true}",
7541
- onEvent: {
7542
- "submitSucc": {
7543
- "weight": 0,
7544
- "actions": [
7545
- {
7546
- "actionType": "broadcast",
7547
- "args": {
7548
- "eventName": `@data.changed.${objectSchema.name}`
7549
- },
7550
- "data": {
7551
- "objectName": `${objectSchema.name}`,
7552
- "displayAs": "${displayAs}"
7601
+ if(api.data.$self._isRelated){
7602
+ const self = api.data.$self;
7603
+ const relatedKey = self.relatedKey;
7604
+ const refField = self.uiSchema.fields[relatedKey];
7605
+ const masterRecord = self._master.record;
7606
+ const masterObjectName = self._master.objectName;
7607
+ let relatedValue = self._master.recordId;
7608
+ if(refField.reference_to_field && refField.reference_to_field != '_id'){
7609
+ relatedValue = masterRecord[refField.reference_to_field]
7610
+ }
7611
+ let relatedFilters;
7612
+ if (
7613
+ refField._reference_to ||
7614
+ (refField.reference_to && !_.isString(refField.reference_to))
7615
+ ) {
7616
+ relatedFilters = [
7617
+ [relatedKey + "/o", "=", masterObjectName],
7618
+ [relatedKey + "/ids", "=", relatedValue],
7619
+ ];
7620
+ } else {
7621
+ relatedFilters = [relatedKey, "=", relatedValue];
7622
+ }
7623
+ userFilters.push(relatedFilters)
7624
+ }
7625
+
7626
+ if(!_.isEmpty(userFilters)){
7627
+ if(_.isEmpty(filters)){
7628
+ filters = userFilters;
7629
+ }else{
7630
+ filters = [filters, 'and', userFilters]
7631
+ }
7632
+ }
7633
+ api.data._ids = _ids;
7634
+ api.data = {
7635
+ query: api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim())
7636
+ }
7637
+ ${options.requestAdaptor || ''}
7638
+ return api;
7639
+ `;
7640
+ api.adaptor = `
7641
+ if(api.body.listName == "recent"){
7642
+ payload.data.rows = _.sortBy(payload.data.rows, function(item){
7643
+ return _.indexOf(api.body._ids, item._id)
7644
+ });
7645
+ }
7646
+ const enable_tree = ${mainObject.enable_tree};
7647
+ if(!enable_tree){
7648
+ _.each(payload.data.rows, function(item, index){
7649
+ const {pageNo, pageSize} = api.body;
7650
+ const skip = (pageNo - 1) * pageSize;
7651
+ item._index = skip + index + 1;
7652
+ })
7653
+ }
7654
+ window.postMessage(Object.assign({type: "listview.loaded"}), "*");
7655
+ let fileFields = ${JSON.stringify(fileFields)};
7656
+ let lookupFields = ${JSON.stringify(lookupFields)};
7657
+ _.each(payload.data.rows, function(item, index){
7658
+ _.each(fileFields , (field, key)=>{
7659
+ if(item[key] && item._display && item._display[key]){
7660
+ let value = item._display[key];
7661
+ if(!_.isArray(value)){
7662
+ value = [value]
7663
+ };
7664
+ if(field.type === 'file'){
7665
+ item[key] = value
7666
+ }else{
7667
+ item[key] = _.map(value, 'url')
7553
7668
  }
7554
- },
7555
- {
7556
- "actionType": "broadcast",
7557
- "args": {
7558
- "eventName": "@data.changed.${_master.objectName}"
7559
- },
7560
- "data": {
7561
- "objectName": "${_master.objectName}",
7562
- "_isRelated": "${_isRelated || _master._isRelated}"
7563
- },
7564
- "expression": `\${_master.objectName != '${objectSchema.name}' && _master.objectName}`
7565
- },
7566
- // {
7567
- // "actionType": "custom",
7568
- // "script": "debugger;"
7569
- // },
7570
- // {
7571
- // "args": {},
7572
- // "actionType": "closeDialog"
7573
- // }
7574
- ]
7575
- }
7669
+ }
7670
+ })
7671
+ _.each(lookupFields , (field, key)=>{
7672
+ if(item[key]){
7673
+ if(field._optionsFunction){
7674
+ const optionsFunction = eval("(" + field._optionsFunction+ ")")(item);
7675
+ item[key + '__label'] = _.map(_.filter(optionsFunction, function(option){return _.includes(item[key], option.value)}), 'label').join(' ');
7676
+ }
7677
+ }
7678
+ })
7679
+ })
7680
+
7681
+ if(enable_tree){
7682
+ const records = payload.data.rows || [];
7683
+ const getTreeOptions = SteedosUI.getTreeOptions
7684
+ payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
7685
+ }
7686
+
7687
+
7688
+ try{
7689
+ // TODO: 不应该直接在这里取localStorage,应该从外面传入
7690
+ const listViewId = api.body.listViewId;
7691
+ const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
7692
+ /**
7693
+ * localListViewProps规范来自crud请求api中api.data.$self参数值的。
7694
+ * 比如:{"perPage":20,"page":1,"__searchable__name":"7","__searchable__between__n1__c":[null,null],"filter":[["name","contains","a"]]}
7695
+ * __searchable__...:顶部放大镜搜索条件
7696
+ * filter:右侧过滤器
7697
+ * perPage:每页条数
7698
+ * page:当前页码
7699
+ * orderBy:排序字段
7700
+ * orderDir:排序方向
7701
+ */
7702
+ let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
7703
+ let selfData = JSON.parse(JSON.stringify(api.body.$self));
7704
+ if(localListViewProps){
7705
+ localListViewProps = JSON.parse(localListViewProps);
7706
+ selfData = Object.assign({}, localListViewProps, selfData, { filter: api.body.filter });
7707
+ if(!api.body.loaded){
7708
+ // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
7709
+ // 所以会把localSearchableFilter中已经存过的页码覆盖
7710
+ // 如果是第一次加载组件始终让翻页页码从本地存储中取值
7711
+ let formFactor = "${options.formFactor}";
7712
+ // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
7713
+ selfData.page = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
7714
+ }
7576
7715
  }
7577
- })]
7578
- };
7579
- if(formSchema.id){
7580
- amisSchema.id = `service-${formSchema.id}`;
7716
+ delete selfData.context;
7717
+ delete selfData.global;
7718
+ sessionStorage.setItem(listViewPropsStoreKey, JSON.stringify(selfData));
7719
+ // 返回页码到UI界面
7720
+ payload.data.page= selfData.page;
7581
7721
  }
7582
- return amisSchema;
7722
+ catch(ex){
7723
+ console.error("本地存储中crud参数解析异常:", ex);
7724
+ }
7725
+ // 标记加载过,后续优先从本地存储中加载相关参数
7726
+ payload.data.loaded= true;
7727
+
7728
+ const setDataToComponentId = "${setDataToComponentId}";
7729
+ if(setDataToComponentId){
7730
+ SteedosUI.getRef(api.body.$self.$scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
7731
+ };
7732
+ ${options.adaptor || ''}
7733
+ return payload;
7734
+ `;
7735
+ return api;
7583
7736
  }
7584
7737
 
7585
- async function getObjectDetail(objectSchema, recordId, ctx){
7586
- const { formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, formInitProps } = ctx;
7587
- const fields = ___default.values(objectSchema.fields);
7588
- const formFields = getFormFields(objectSchema, ctx);
7589
- const serviceId = `service_detail_page`;
7738
+ async function getApi(object, recordId, fields, options){
7739
+ const data = await getFindQuery(object, recordId, fields, options);
7590
7740
  return {
7591
- type: 'service',
7592
- name: `page_readonly_${recordId}`,
7593
- id: serviceId,
7594
- data: {global: getGlobalData('read'), context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
7595
- api: await getReadonlyFormInitApi(objectSchema, recordId, fields, formInitProps),
7596
- body: [
7597
- {
7598
- "type": "wrapper", //form 的 hiddenOn 会导致 form onEvent 异常, 使用wrapper包裹一次form,并在wrapper上控制显隐
7599
- hiddenOn: "${recordLoaded != true}",
7600
- "className": "p-0 m-0",
7601
- "body": {
7602
- type: "form",
7603
- mode: layout,
7604
- labelAlign,
7605
- persistData: false,
7606
- promptPageLeave: false,
7607
- name: `form_readonly_${recordId}`,
7608
- debug: false,
7609
- title: "",
7610
- data: {
7611
- "formData": "$$"
7612
- },
7613
- wrapWithPanel: false,
7614
- body: await getFormBody(map(fields, (field)=>{field.readonly = true; return field;}), map(formFields, (field)=>{field.readonly = true; return field;}), Object.assign({}, ctx, {showSystemFields: true})),
7615
- className: 'steedos-amis-form bg-white',
7616
- actions: [], // 不显示表单默认的提交按钮
7617
- onEvent: {
7618
- [`@data.changed.${objectSchema.name}`]: { // 由于amis service 组件的 onEvent 存在bug ,此处借助form来刷新 上层 service https://github.com/baidu/amis/issues/6294
7619
- "actions": [
7620
- {
7621
- "actionType": "reload",
7622
- "componentId": serviceId,
7623
- "expression": "this.__deletedRecord != true"
7624
- },
7625
- {
7626
- // "args": {
7627
- // "url": "/app/${appId}/${objectName}/grid/${side_listview_id}",
7628
- // "blank": false
7629
- // },
7630
- "actionType": "custom",
7631
- "script": "Steedos.goBack()",
7632
- "expression": "this.__deletedRecord === true"
7633
- }
7634
- ]
7635
- }
7636
- }
7637
- },
7638
- }
7639
- ],
7640
- onEvent: {
7641
- "fetchInited": {
7642
- "weight": 0,
7643
- "actions": [
7644
- {
7645
- actionType: 'broadcast',
7646
- eventName: "recordLoaded",
7647
- args: {
7648
- eventName: "recordLoaded"
7649
- },
7650
- data: {
7651
- objectName: "${event.data.__objectName}",
7652
- record: "${event.data.__record}"
7653
- },
7654
- expression: "${event.data.__response.error != true}"
7655
- },
7656
- {
7657
- "actionType": "setValue",
7658
- "args": {
7659
- value: {
7660
- "recordLoaded": true,
7661
- }
7662
- },
7663
- expression: "${event.data.__response.error != true}"
7664
- }
7665
- ]
7666
- }
7741
+ method: "post",
7742
+ url: getApi$2(), // + "&recordId=${recordId}"
7743
+ data: data,
7744
+ headers: {
7745
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7667
7746
  }
7668
7747
  }
7669
7748
  }
7670
7749
 
7671
- /*
7672
- * @Author: baozhoutao@steedos.com
7673
- * @Date: 2022-08-04 10:42:49
7674
- * @LastEditors: baozhoutao@steedos.com
7675
- * @LastEditTime: 2022-08-25 10:28:47
7676
- * @Description:
7677
- */
7678
- var config = {
7679
- listView: {
7680
- newRecordMode: 'modal',
7681
- editRecordMode: 'modal',
7682
- perPage: 20
7750
+ function getRecordPermissionsApi(object, recordId, options){
7751
+ const data = getRecordPermissionsQuery(object, recordId, options);
7752
+ return {
7753
+ method: "post",
7754
+ url: getApi$2(),
7755
+ data: data,
7756
+ headers: {
7757
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7758
+ }
7683
7759
  }
7684
- };
7760
+ }
7685
7761
 
7686
- async function getTableColumns(fields, options){
7687
- const columns = [{name: '_index',type: 'text', width: 32, placeholder: ""}];
7688
- for (const field of fields) {
7689
- if((field.is_name || field.name === options.labelFieldName) && options.objectName === 'cms_files'){
7690
- const previewFileScript = `
7691
- var data = event.data;
7692
- var file_name = data.versions ? data.name : "${field.label}";
7693
- var file_id = data._id;
7694
- SteedosUI.previewFile && SteedosUI.previewFile({file_name, file_id});
7695
- `;
7696
- columns.push({
7697
- "type": "button",
7698
- "label": `<%=data.versions ? data.name : "${field.label}"%>`,
7699
- "className": "whitespace-nowrap",
7700
- "level": "link",
7701
- "onEvent": {
7702
- "click": {
7703
- "actions": [
7704
- {
7705
- "args": {
7706
- "api": {
7707
- "url": "${context.rootUrl}/api/files/files/${versions[0]}?download=true",
7708
- "method": "get",
7709
- "headers": {
7710
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
7711
- }
7712
- }
7713
- },
7714
- "actionType": "download",
7715
- "expression": "!!!window?.nw?.require"//浏览器上直接下载
7716
- },
7717
- {
7718
- "args": {},
7719
- "actionType": "custom",
7720
- "script": previewFileScript,
7721
- "expression": "!!window?.nw?.require" //PC客户端预览附件
7722
- }
7723
- ]
7724
- }
7725
- }
7726
- });
7727
- }else if(field.type === 'toggle'){
7728
- columns.push(Object.assign({}, {
7729
- type: "switch",
7730
- name: field.name,
7731
- label: field.label,
7732
- width: field.width,
7733
- toggled: field.toggled,
7734
- disabled: true,
7735
- className:"whitespace-nowrap",
7736
- }, field.amis, {name: field.name}));
7737
- }else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7738
- columns.push(Object.assign({}, {
7739
- type: "switch",
7740
- name: field.name,
7741
- label: field.label,
7742
- width: field.width,
7743
- toggled: field.toggled,
7744
- disabled: true,
7745
- className:"whitespace-nowrap",
7746
- ...getAmisFileReadonlySchema(field)
7747
- }, field.amis, {name: field.name}));
7748
- }
7749
- else if(field.type === 'select'){
7750
- const map = getSelectMap(field.options);
7751
- columns.push(Object.assign({}, {
7752
- type: "mapping",
7753
- name: field.name,
7754
- label: field.label,
7755
- map: map,
7756
- sortable: field.sortable,
7757
- width: field.width,
7758
- toggled: field.toggled,
7759
- className:"whitespace-nowrap",
7760
- }, field.amis, {name: field.name}));
7761
- }
7762
- else {
7763
- const tpl = await getFieldTpl(field, options);
7762
+ const API_CACHE = 100;
7764
7763
 
7765
- let type = 'text';
7766
- if(tpl){
7767
- type = 'tpl';
7768
- }else if(field.type === 'html'){
7769
- type = 'markdown';
7770
- }else if(field.type === 'url' && field.show_as_qr){
7771
- type = 'qr-code';
7772
- }
7773
- let className = "";
7774
- if(field.type === 'textarea'){
7775
- className = 'min-w-56';
7776
- }
7777
- if(field.wrap === false){
7778
- className += " whitespace-nowrap";
7764
+ function getReadonlyFormAdaptor(object, fields){
7765
+ let scriptStr = '';
7766
+ const selectFields = _$1.filter(fields, function(field){return field.name.indexOf('.') < 0 && ((field.type == 'select' && field.options) || ((field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to))});
7767
+ const gridAndObjectFieldsName = _$1.map(_$1.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type === 'object' || field.type === 'grid')}), 'name');
7768
+ _$1.each(selectFields, function(field){
7769
+ if(!_$1.includes(OMIT_FIELDS, field.name)){
7770
+ field.name;
7771
+ if(field.options){
7772
+ const options = JSON.stringify({options: field.options});
7773
+ scriptStr = scriptStr + `var ${field.name}Options= (${options}).options;`;
7774
+ }else if(field.optionsFunction){
7775
+ scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`;
7776
+ }else if(field._optionsFunction){
7777
+ scriptStr = scriptStr + `var ${field.name}Options = eval(${field._optionsFunction})(api.data);`;
7779
7778
  }
7780
- if(!field.hidden && !field.extra){
7781
- columns.push(Object.assign({}, {
7782
- name: field.name,
7783
- label: field.label,
7784
- sortable: field.sortable,
7785
- // searchable: field.searchable,
7786
- width: field.width,
7787
- type: type,
7788
- tpl: tpl,
7789
- toggled: field.toggled,
7790
- className,
7791
- options: field.type === 'html' ? {html: true} : null
7792
- // toggled: true
7793
- }, field.amis, {name: field.name}));
7779
+ if(field.multiple){
7780
+ scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`;
7781
+ }else {
7782
+ scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`;
7783
+ scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`;
7794
7784
  }
7795
7785
  }
7796
-
7797
- }
7798
- // columns.push(getOperation(fields));
7799
- if(!_$1.some(columns, { name: options.labelFieldName })){
7800
- const href = Router.getObjectDetailPath({
7801
- ...options, formFactor: options.formFactor, appId: "${appId}", objectName: options.objectName || "${objectName}", recordId: `\${${options.idFieldName}}`
7802
- });
7803
- columns[0].type = "tpl";
7804
- columns[0].tpl = `<a href="${href}">\${${columns[0].name}}</a>`;
7786
+ });
7787
+
7788
+ // const refFields = _.filter(fields, function(field){return field.name.indexOf('.') < 0 && (field.type == 'lookup' || field.type == 'master_detail') && !field.reference_to});
7789
+ // _.each(refFields, function(field){
7790
+ // if(!_.includes(OMIT_FIELDS, field.name)){
7791
+ // const valueField = field.reference_to_field || '_id';
7792
+ // scriptStr = scriptStr + `var ${field.name}Options = eval(${field.optionsFunction.toString()})(api.data);`
7793
+ // if(field.multiple){
7794
+ // scriptStr = scriptStr + `data.${field.name}__label = _.map(_.filter(${field.name}Options, function(option){return _.includes(data.${field.name}, option.value)}), 'label');`
7795
+ // }else{
7796
+ // scriptStr = scriptStr + `var ${field.name}Selected = _.find(${field.name}Options, function(option){return data.${field.name} == option.value});`
7797
+ // scriptStr = scriptStr + `data.${field.name}__label = ${field.name}Selected ? ${field.name}Selected.label:null;`
7798
+ // }
7799
+ // }
7800
+ // })
7801
+
7802
+ return `
7803
+ if(payload.data.data.length === 0){
7804
+ return {
7805
+ status: 2,
7806
+ msg: "无法找到记录"
7807
+ }
7808
+ }
7809
+ if(payload.data.data){
7810
+ var data = payload.data.data[0];
7811
+ var gridAndObjectFieldsName = ${JSON.stringify(gridAndObjectFieldsName)};
7812
+ try{
7813
+ ${scriptStr}
7814
+ ${getScriptForAddUrlPrefixForImgFields(fields)}
7815
+ ${getScriptForRewriteValueForFileFields(fields)}
7816
+ }catch(e){
7817
+ console.error(e)
7818
+ }
7819
+ // 原始记录
7820
+ var record = _.cloneDeep(data);
7821
+ try{
7822
+ _.each(gridAndObjectFieldsName, function(name){
7823
+ data[name] = data._display[name];
7824
+ })
7825
+ }catch(e){
7826
+ console.error(e)
7827
+ }
7828
+ payload.data = data;
7829
+ payload.data.__objectName = "${object.name}";
7830
+ payload.data.__record = record;
7831
+ window.postMessage(Object.assign({type: "record.loaded"}, {record: record}), "*")
7832
+ }
7833
+ if(payload.errors){
7834
+ payload.status = 2;
7835
+ payload.msg = payload.errors[0].message;
7836
+ }
7837
+ return payload;
7838
+ `
7839
+ }
7840
+
7841
+ async function getReadonlyFormInitApi(object, recordId, fields, options){
7842
+ return {
7843
+ method: "post",
7844
+ url: getApi$2()+"&recordId=${recordId}",
7845
+ cache: API_CACHE,
7846
+ // requestAdaptor: "console.log('getReadonlyFormInitApi requestAdaptor', api);return api;",
7847
+ adaptor: getReadonlyFormAdaptor(object, fields),
7848
+ data: await getFindOneQuery$1(object, recordId, fields, options),
7849
+ headers: {
7850
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7851
+ }
7805
7852
  }
7806
- return columns;
7807
7853
  }
7808
7854
 
7809
- /**
7810
- * 生成移动端列表每行显示的amis
7811
- * @param {*} tpls 要显示的每个字段的tpl
7812
- * @returns {
7813
- "type": "wrapper",
7814
- "body": [{
7815
- "type": "tpl",
7816
- "tpl": tpls[index].tpl,
7817
- "className": "truncate"//左侧样式类
7818
- },{
7819
- "type": "tpl",
7820
- "tpl": tpls[index + 1].tpl,
7821
- "className": "truncate ml-2 flex flex-shrink-0"//右侧样式类
7822
- }],
7823
- "size": "none",
7824
- "className": "flex items-center justify-between"//每行样式类
7855
+ /*
7856
+ img/avatar字段值添加URL前缀使其在amis中正常显示图片。
7857
+ */
7858
+ function getScriptForAddUrlPrefixForImgFields(fields){
7859
+ let imgFieldsKeys = [];
7860
+ let imgFields = {};
7861
+ fields.forEach((item)=>{
7862
+ if(_$1.includes(['image','avatar'], item.type)){
7863
+ imgFieldsKeys.push(item.name);
7864
+ imgFields[item.name] = {
7865
+ name: item.name,
7866
+ type: item.type,
7867
+ multiple: item.multiple
7868
+ };
7869
+ }
7870
+ });
7871
+ if(!imgFieldsKeys.length){
7872
+ return '';
7825
7873
  }
7826
- */
7827
- function getMobileLines(tpls){
7828
- let lines = [];
7829
- let maxLineCount = 2;
7830
- let lineChildren = [];
7831
- let isNewLine = false;
7832
- let isLeft = true;
7833
- let lineChildrenClassName = "";
7834
- let lineClassName = "flex items-center justify-between h-[20px]";
7835
- tpls.forEach(function(item){
7836
- if(isNewLine && lines.length < maxLineCount){
7837
- lines.push({
7838
- "type": "wrapper",
7839
- "body": lineChildren,
7840
- "size": "none",
7841
- "className": lineClassName
7842
- });
7843
- lineChildren = [];
7874
+ return `
7875
+ // image字段值添加URL前缀
7876
+ let imgFieldsKeys = ${JSON.stringify(imgFieldsKeys)};
7877
+ let imgFields = ${JSON.stringify(imgFields)};
7878
+ imgFieldsKeys.forEach((item)=>{
7879
+ let imgFieldValue = data[item];
7880
+ let imgFieldDisplayValue = data._display && data._display[item];
7881
+ if(imgFieldValue && imgFieldValue.length){
7882
+ let fieldProps = imgFields[item];
7883
+ if(fieldProps.multiple){
7884
+ if(imgFieldDisplayValue instanceof Array){
7885
+ data[item] = imgFieldDisplayValue.map((i)=>{ return i.url });
7886
+ }
7887
+ }else{
7888
+ data[item] = imgFieldDisplayValue && imgFieldDisplayValue.url;
7889
+ }
7890
+ }
7891
+ })
7892
+ `
7893
+ }
7894
+
7895
+ /*
7896
+ file字段值重写使其在amis中正常显示附件名、点击附件名下载文件。
7897
+ */
7898
+ function getScriptForRewriteValueForFileFields(fields){
7899
+ let fileFieldsKeys = [];
7900
+ let fileFields = {};
7901
+ fields.forEach((item)=>{
7902
+ if(item.type === 'file'){
7903
+ fileFieldsKeys.push(item.name);
7904
+ fileFields[item.name] = {
7905
+ name: item.name,
7906
+ multiple: item.multiple
7907
+ };
7844
7908
  }
7845
- if(isLeft){
7846
- // 左侧半行
7847
- lineChildrenClassName = "steedos-listview-item-left truncate";
7848
- if(item.field.is_wide){
7849
- // 左侧全行样式可以单独写
7850
- lineChildrenClassName = "steedos-listview-item-wide truncate";
7851
- }
7852
- if(lines.length === 0){
7853
- // 第一个字段加粗黑色显示
7854
- lineChildrenClassName += " font-bold text-gray-800";
7909
+ });
7910
+ if(!fileFieldsKeys.length){
7911
+ return '';
7912
+ }
7913
+ return `
7914
+ // file字段值重写以便编辑时正常显示附件名、点击附件名正常下载附件
7915
+ let fileFieldsKeys = ${JSON.stringify(fileFieldsKeys)};
7916
+ let fileFields = ${JSON.stringify(fileFields)};
7917
+ fileFieldsKeys.forEach((item)=>{
7918
+ let fileFieldValue = data[item];
7919
+ let fileFieldDisplayValue = data._display && data._display[item];
7920
+ if(fileFieldValue && fileFieldValue.length){
7921
+ if(fileFields[item].multiple){
7922
+ if(fileFieldDisplayValue instanceof Array){
7923
+ data[item] = fileFieldDisplayValue.map((item, index)=>{
7924
+ return {
7925
+ value: fileFieldValue[index],
7926
+ name: item.name,
7927
+ url: item.url + "?download=true",
7928
+ state: "uploaded"
7929
+ }
7930
+ });
7931
+ }
7932
+ }else{
7933
+ data[item] = [{
7934
+ value: fileFieldValue,
7935
+ name: fileFieldDisplayValue.name,
7936
+ url: fileFieldDisplayValue.url + "?download=true",
7937
+ state: "uploaded"
7938
+ }];
7939
+ }
7940
+ }
7941
+ })
7942
+ `
7943
+ }
7944
+
7945
+ async function getEditFormInitApi(object, recordId, fields, options){
7946
+ const data = await getFindOneQuery$1(object, recordId, fields);
7947
+ data.recordId = "${recordId}";
7948
+ data.objectName = "${objectName}";
7949
+ data.uiSchema = "${uiSchema}";
7950
+ data.global = "${global}";
7951
+ data.context = "${context}";
7952
+ data.defaultData = "${defaultData}";
7953
+ data._master = "${_master}";
7954
+
7955
+ return {
7956
+ method: "post",
7957
+ url: getApi$2() + '&objectName=${objectName}' ,
7958
+ // sendOn: "!!this.recordId",
7959
+ cache: API_CACHE,
7960
+ requestAdaptor: `
7961
+ // 所有不想在network请求中发送的数据都应该从data中分离出来,data变量只需要留下query才需要发送出去
7962
+ var { recordId, objectName, uiSchema, global, context, ...data} = api.data;
7963
+ if(!recordId){
7964
+ // 新建则不请求任何数据
7965
+ data.query = "{data:" + objectName + "(filters: " + JSON.stringify(["_id", "=", null]) + ", top: 1){_id}}";
7855
7966
  }
7856
- }
7857
- else {
7858
- // 右侧半行
7859
- lineChildrenClassName = "steedos-listview-item-right truncate ml-2 flex flex-shrink-0";
7860
- }
7861
- lineChildren.push({
7862
- "type": "tpl",
7863
- "tpl": item.tpl,
7864
- "className": lineChildrenClassName
7865
- });
7967
+ api.data = data;
7968
+ ${options.initApiRequestAdaptor || ''}
7969
+ return api;
7970
+ `,
7971
+ adaptor: `
7972
+ const recordId = api.body.recordId;
7973
+ let initialValues={};
7974
+ if(recordId && payload.data.data){
7975
+ var data = payload.data.data[0];
7976
+ const dataKeys = _.keys(data);
7977
+ const uiSchema = api.body.uiSchema;
7978
+ const fieldKeys = uiSchema && _.keys(uiSchema.fields);
7866
7979
 
7867
- if(item.field.is_wide){
7868
- // 宽字段占整行
7869
- isLeft = true;
7870
- isNewLine = true;
7871
- }
7872
- else {
7873
- isLeft = !isLeft;
7874
- isNewLine = isLeft;
7980
+ if(data){
7981
+ ${getScriptForAddUrlPrefixForImgFields(fields)}
7982
+ ${getScriptForRewriteValueForFileFields(fields)}
7983
+
7984
+ _.each(dataKeys, function(key){
7985
+ if(fieldKeys.indexOf(key)<0){
7986
+ delete data[key];
7987
+ }
7988
+ })
7989
+
7990
+ //初始化接口返回的字段移除字段值为null的字段
7991
+ for (key in data){
7992
+ if(data[key] === null){
7993
+ delete data[key];
7994
+ }
7995
+ }
7996
+ };
7997
+ initialValues = data;
7998
+ }
7999
+ else{
8000
+ var uiSchema = api.body.uiSchema;
8001
+ var defaultData = api.body.defaultData;
8002
+ var defaultValues = {};
8003
+ _.each(uiSchema?.fields, function(field){
8004
+ var value = SteedosUI.getFieldDefaultValue(field, api.body.global);
8005
+ if(value){
8006
+ defaultValues[field.name] = value;
8007
+ }
8008
+ });
8009
+ if(defaultData && _.isObject(defaultData) && !_.isArray(defaultData)){
8010
+ defaultValues = Object.assign({}, defaultValues, defaultData)
8011
+ }
8012
+ if(uiSchema.form){
8013
+ try{
8014
+ var objectFormConfig = JSON.parse(uiSchema.form);
8015
+ var formInitialValuesFun = objectFormConfig.initialValues;
8016
+ if(formInitialValuesFun){
8017
+ formInitialValuesFun = new Function("return " + formInitialValuesFun)();
8018
+ }
8019
+ if(typeof formInitialValuesFun === "function"){
8020
+ initialValues = formInitialValuesFun.apply({doc: defaultValues || {} , global: api.body.global, master: api.body._master })
8021
+ }
8022
+ }
8023
+ catch(ex){
8024
+ console.warn(ex);
8025
+ }
8026
+ }
8027
+ if(_.isObject(initialValues)){
8028
+ // uiSchema.form.initialValues为函数且执行后为json,则优先取initialValues中的默认值
8029
+ initialValues = Object.assign({}, defaultValues, initialValues);
8030
+ }
8031
+ else{
8032
+ initialValues = defaultValues;
8033
+ }
8034
+ }
8035
+ // data下的变量需要在保存接口(getSaveApi)中被删除。
8036
+ payload.data = {
8037
+ ...initialValues
8038
+ }
8039
+ ${options.initApiAdaptor || ''}
8040
+ return payload;
8041
+ `,
8042
+ responseData: {
8043
+ initialValues: "$$",
8044
+ editFormInited: true
8045
+ },
8046
+ data: data,
8047
+ headers: {
8048
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7875
8049
  }
7876
- });
7877
-
7878
- if(lineChildren.length && lines.length < maxLineCount){
7879
- lines.push({
7880
- "type": "wrapper",
7881
- "body": lineChildren,
7882
- "size": "none",
7883
- "className": lineClassName
7884
- });
7885
8050
  }
7886
-
7887
- return lines;
7888
8051
  }
7889
8052
 
7890
- async function getMobileTableColumns(fields, options){
7891
- const columns = [];
7892
- let nameField = {};
7893
- let tpls = [];
7894
- for (const field of fields) {
7895
- let tpl = "";
7896
- if(field.is_name || field.name === options.labelFieldName){
7897
- nameField = field;
7898
- options.onlyDisplayLabel = true;
7899
- tpl = await getFieldTpl(field, options);
7900
- }
7901
- else if(field.type === 'avatar' || field.type === 'image' || field.type === 'file'){
7902
- // 图片和附件类型字段暂时显示为附件名称,后续需要再优化
7903
- tpl = `\${_display.${field.name}.name}`;
7904
- }
7905
- else {
7906
- if(field.type === 'lookup' || field.type === 'master_detail'){
7907
- options.onlyDisplayLabel = true;
8053
+
8054
+ function getSaveApi(object, recordId, fields, options){
8055
+ return {
8056
+ method: 'post',
8057
+ url: getApi$2(),
8058
+ data: getSaveQuery(object, recordId),
8059
+ requestAdaptor: getSaveRequestAdaptor(fields, options),
8060
+ responseData: {
8061
+ "recordId": "${record._id}"
8062
+ },
8063
+ adaptor: `
8064
+ if(payload.errors){
8065
+ payload.status = 2;
8066
+ payload.msg = window.t ? window.t(payload.errors[0].message) : payload.errors[0].message;
7908
8067
  }
7909
- tpl = await getFieldTpl(field, options);
7910
- }
7911
- if(!tpl){
7912
- tpl = `\${${field.name}}`;
8068
+ ${options.apiAdaptor || ''}
8069
+ return payload;
8070
+ `,
8071
+ headers: {
8072
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7913
8073
  }
7914
- if(!field.hidden && !field.extra){
7915
- tpls.push({ field, tpl });
8074
+ }
8075
+ }
8076
+
8077
+ function getBatchDelete(objectName){
8078
+ return {
8079
+ method: 'post',
8080
+ url: getApi$2(),
8081
+ requestAdaptor: `
8082
+ var ids = api.data.ids.split(",");
8083
+ var deleteArray = [];
8084
+ ids.forEach((id,index)=>{
8085
+ deleteArray.push(\`delete__\${index}:${objectName}__delete(id: "\${id}")\`);
8086
+ })
8087
+ api.data = {query: \`mutation{\${deleteArray.join(',')}}\`};
8088
+ return api;
8089
+ `,
8090
+ data: {
8091
+ ids: `\${ids}`
8092
+ },
8093
+ headers: {
8094
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
7916
8095
  }
7917
8096
  }
7918
- const url = getNameTplUrl(nameField, options);
8097
+ }
7919
8098
 
7920
- const columnLines = getMobileLines(tpls);
8099
+ const DEFAULT_CALENDAR_OPTIONS = {
8100
+ startDateExpr: "start",
8101
+ endDateExpr: "end",
8102
+ allDayExpr: "is_all_day",
8103
+ textExpr: "name"
8104
+ };
8105
+
8106
+ async function getCalendarApi(mainObject, fields, options) {
8107
+ if (!options) {
8108
+ options = {};
8109
+ }
8110
+ const calendarOptions = options.calendarOptions;
8111
+ const searchableFields = [];
8112
+ let { filter, sort, top, setDataToComponentId = '' } = options;
7921
8113
 
8114
+ if (!top) {
8115
+ // 日历请求不翻页
8116
+ top = 200;
8117
+ }
7922
8118
 
7923
- let column = {
7924
- name: nameField.name,
7925
- label: nameField.label,
7926
- sortable: nameField.sortable,
7927
- type: "button",
7928
- level: "link",
7929
- actionType: "link",
7930
- link: url,
7931
- innerClassName: "steedos-listview-item block text-gray-500",
7932
- body: {
7933
- "type": "wrapper",
7934
- "body": columnLines,
7935
- "size": "none",
7936
- "className": "p-1"
8119
+ if (___default.isArray(filter)) {
8120
+ filter = ___default.map(filter, function (item) {
8121
+ if (item.operation) {
8122
+ return [item.field, item.operation, item.value];
8123
+ } else {
8124
+ return item
8125
+ }
8126
+ });
8127
+ }
8128
+ if (!filter) {
8129
+ filter = [];
8130
+ }
8131
+
8132
+ ___default.each(fields, function (field) {
8133
+ if (field.searchable) {
8134
+ searchableFields.push(field.name);
8135
+ }
8136
+ });
8137
+
8138
+ const idFieldName = mainObject.idFieldName || "_id";
8139
+ let valueField = mainObject.key_field || '_id';
8140
+ const api = await getApi(mainObject, null, fields, { alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"` });
8141
+ api.data.$term = "$term";
8142
+ api.data.$self = "$$";
8143
+ api.data.filter = "$filter";
8144
+ api.data.pageSize = top || 10;
8145
+ api.requestAdaptor = `
8146
+ let selfData = JSON.parse(JSON.stringify(api.data.$self));
8147
+ var filters = api.data.filter || ${JSON.stringify(filter)} || [];
8148
+ const eventFetchInfo = selfData.fetchInfo;
8149
+ const startDateExpr = "${calendarOptions.startDateExpr}";
8150
+ const endDateExpr = "${calendarOptions.endDateExpr}";
8151
+ const eventDurationFilters = [[endDateExpr, ">=", eventFetchInfo.start], [startDateExpr, "<=", eventFetchInfo.end]];
8152
+ if(_.isEmpty(filters)){
8153
+ filters = eventDurationFilters;
8154
+ }else{
8155
+ filters = [filters, 'and', eventDurationFilters]
8156
+ }
8157
+
8158
+ if(api.data.$self.additionalFilters){
8159
+ filters.push(api.data.$self.additionalFilters)
8160
+ }
8161
+
8162
+ var pageSize = api.data.pageSize || 10;
8163
+ var pageNo = api.data.pageNo || 1;
8164
+ var skip = (pageNo - 1) * pageSize;
8165
+ var orderBy = api.data.orderBy || '';
8166
+ var orderDir = api.data.orderDir || '';
8167
+ var sort = orderBy + ' ' + orderDir;
8168
+ sort = orderBy ? sort : "${sort}";
8169
+ var allowSearchFields = ${JSON.stringify(searchableFields)};
8170
+ if(api.data.$term){
8171
+ filters = [["name", "contains", "'+ api.data.$term +'"]];
8172
+ }else if(selfData.op === 'loadOptions' && selfData.value){
8173
+ filters = [["${valueField.name}", "=", selfData.value]];
8174
+ }
8175
+ var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
8176
+
8177
+ if(searchableFilter.length > 0){
8178
+ if(filters.length > 0 ){
8179
+ filters = [filters, 'and', searchableFilter];
8180
+ }else{
8181
+ filters = searchableFilter;
7937
8182
  }
7938
- };
7939
-
7940
- if(options.objectName === 'cms_files'){
7941
- if(window.Meteor?.isCordova){
7942
- column = {
7943
- ...column,
7944
- actionType: "",
7945
- link: "",
7946
- onEvent: {
7947
- "click": {
7948
- "actions": [
7949
- {
7950
- "script": `
7951
- let cms_url = "/api/files/files/"+event.data.versions[0]+"?download=true"
7952
- Steedos.cordovaDownload(encodeURI(Steedos.absoluteUrl(cms_url)), event.data.name);
7953
- `,
7954
- "actionType": "custom"
7955
- }
7956
- ],
7957
- "weight": 0
7958
- }
7959
- }
7960
- };
7961
- }else {
7962
- column = {
7963
- ...column,
7964
- actionType: "",
7965
- link: "",
7966
- onEvent: {
7967
- "click": {
7968
- "actions": [
7969
- {
7970
- "args": {
7971
- "api": {
7972
- "url": url,
7973
- "method": "get",
7974
- "headers": {
7975
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
7976
- }
7977
- }
7978
- },
7979
- "actionType": "download"
7980
- }
7981
- ],
7982
- "weight": 0
7983
- }
8183
+ }
8184
+
8185
+ if(allowSearchFields){
8186
+ allowSearchFields.forEach(function(key){
8187
+ const keyValue = selfData[key];
8188
+ if(_.isString(keyValue)){
8189
+ filters.push([key, "contains", keyValue]);
8190
+ }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8191
+ filters.push([key, "=", keyValue]);
8192
+ }
8193
+ })
8194
+ }
8195
+
8196
+ if(selfData.__keywords && allowSearchFields){
8197
+ const keywordsFilters = [];
8198
+ allowSearchFields.forEach(function(key, index){
8199
+ const keyValue = selfData.__keywords;
8200
+ if(keyValue){
8201
+ keywordsFilters.push([key, "contains", keyValue]);
8202
+ if(index < allowSearchFields.length - 1){
8203
+ keywordsFilters.push('or');
7984
8204
  }
7985
- };
7986
- }
7987
-
8205
+ }
8206
+ })
8207
+ filters.push(keywordsFilters);
8208
+ }
8209
+ api.data.query = api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim());
8210
+ delete api.data.$term;
8211
+ delete api.data.filter;
8212
+ delete api.data.pageSize;
8213
+ delete api.data.pageNo;
8214
+ delete api.data.orderBy;
8215
+ delete api.data.orderDir;
8216
+ return api;
8217
+ `;
8218
+ api.adaptor = `
8219
+ window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8220
+ const setDataToComponentId = "${setDataToComponentId}";
8221
+ if(setDataToComponentId){
8222
+ SteedosUI.getRef(api.body.$self.scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
7988
8223
  }
7989
-
7990
- columns.push(column);
7991
-
7992
-
7993
- return columns;
8224
+ const rows = payload.data.rows || [];
8225
+ const selfData = api.data.$self;
8226
+ const events = rows.map(function(n){
8227
+ return {
8228
+ id: n["${idFieldName}"],
8229
+ title: n["${calendarOptions.textExpr}"],
8230
+ start: n["${calendarOptions.startDateExpr}"],
8231
+ end: n["${calendarOptions.endDateExpr}"],
8232
+ allDay: n["${calendarOptions.allDayExpr}"],
8233
+ extendedProps: n
8234
+ }
8235
+ });
8236
+ const successCallback = selfData.successCallback;
8237
+ const failureCallback = selfData.failureCallback;
8238
+ successCallback(events);
8239
+ return payload;
8240
+ `;
8241
+ return api;
7994
8242
  }
7995
8243
 
7996
- function getDefaultParams(options){
7997
- return {
7998
- perPage: options.top || options.perPage || config.listView.perPage
8244
+ function getCalendarRecordPermissionsApi(mainObject, recordId) {
8245
+ const api = getRecordPermissionsApi(mainObject, recordId, { alias: 'rows', limit: 1, fields: ["allowEdit"] });
8246
+ api.data.$self = "$$";
8247
+ api.adaptor = `
8248
+ const rows = payload.data.rows || [];
8249
+ const selfData = api.data.$self;
8250
+ const revert = selfData.revert;
8251
+ const recordPermissions = rows[0] && rows[0].recordPermissions;
8252
+ const editable = !!(recordPermissions && recordPermissions.allowEdit);
8253
+ if(!editable){
8254
+ // 没有权限时还原
8255
+ revert && revert();
7999
8256
  }
8257
+ payload.data.editable = editable;
8258
+ return payload;
8259
+ `;
8260
+ return api;
8000
8261
  }
8001
8262
 
8002
- function getButtonVisibleOn(button){
8003
- let visible= button.visible;
8004
-
8005
- if(button._visible){
8006
- visible = button._visible;
8007
- }
8008
-
8009
- if(isBoolean(visible)){
8010
- visible = visible.toString();
8011
- }
8012
-
8013
- if(visible){
8014
- // if(visible.indexOf("Meteor.") > 0 || visible.indexOf("Creator.") > 0 || visible.indexOf("Session.") > 0){
8015
- // console.warn('无效的visible', visible)
8016
- // return 'false';
8017
- // }
8018
- if(visible.trim().startsWith('function')){
8019
- return `${visible}(objectName, typeof _id === 'undefined' ? null: _id, typeof record === 'undefined' ? (typeof recordPermissions === 'undefined' ? {} : recordPermissions) : record.recordPermissions, data)`
8020
- }
8021
- return visible;
8022
- }
8263
+ function getCalendarRecordSaveApi(object, calendarOptions) {
8264
+ const formData = {};
8265
+ const idFieldName = object.idFieldName || "_id";
8266
+ formData[idFieldName] = "${event.data.event.id}";
8267
+ const nameFieldKey = object.NAME_FIELD_KEY || "name";
8268
+ formData[nameFieldKey] = "${event.data.event.title}";
8269
+ formData[calendarOptions.startDateExpr] = "${event.data.event.start}";
8270
+ formData[calendarOptions.endDateExpr] = "${event.data.event.end}";
8271
+ formData[calendarOptions.allDayExpr] = "${event.data.event.allDay}";
8272
+ // formData[calendarOptions.textExpr] = "${event.data.event.title}";
8273
+ const apiData = {
8274
+ objectName: "${objectName}",
8275
+ $: formData,
8276
+ $self: "$$"
8277
+ };
8278
+ const saveDataTpl = `
8279
+ const formData = api.data.$;
8280
+ const objectName = api.data.objectName;
8281
+ let query = \`mutation{record: \${objectName}__update(id: "\${formData.${idFieldName}}", doc: {__saveData}){${idFieldName}}}\`;
8282
+ delete formData.${idFieldName};
8283
+ let __saveData = JSON.stringify(JSON.stringify(formData));
8284
+ `;
8285
+ const requestAdaptor = `
8286
+ ${saveDataTpl}
8287
+ api.data.query = query.replace('{__saveData}', __saveData);
8288
+ return api;
8289
+ `;
8023
8290
 
8024
- if(button.type === 'amis_button'){
8025
- const amisSchema = button.amis_schema;
8026
- if(amisSchema && amisSchema.body && amisSchema.body.length > 0){
8027
- const btn1 = amisSchema.body[0];
8028
- return btn1.visibleOn
8291
+ return {
8292
+ method: 'post',
8293
+ url: getApi$2(),
8294
+ data: apiData,
8295
+ requestAdaptor: requestAdaptor,
8296
+ adaptor: `
8297
+ if(payload.errors){
8298
+ payload.status = 2;
8299
+ payload.msg = payload.errors[0].message;
8300
+ const revert = api.data.$self.event.data.revert;
8301
+ revert && revert();
8029
8302
  }
8303
+ return payload;
8304
+ `,
8305
+ headers: {
8306
+ Authorization: "Bearer ${context.tenantId},${context.authToken}"
8030
8307
  }
8308
+ };
8031
8309
  }
8032
8310
 
8033
- async function getTableOperation(ctx){
8034
- const buttons = ctx.buttons;
8035
- const operationButtons = [];
8036
- each(buttons, (button)=>{
8037
- if(isBoolean(button.visible)){
8038
- button.visible = button.visible.toString();
8039
- }
8040
- // operationButtons.push({
8041
- // type: 'button',
8042
- // label: button.label,
8043
- // visibleOn: button.visible ? `${button.visible}` : (button._visible ? `${button._visible}` : null),
8044
- // onEvent: {
8045
- // click: {
8046
- // actions: []
8047
- // }
8048
- // }
8049
- // })
8311
+ /**
8312
+ * 列表视图Calendar amisSchema
8313
+ * @param {*} objectSchema 对象UISchema
8314
+ * @returns amisSchema
8315
+ */
8316
+ async function getObjectCalendar(objectSchema, calendarOptions, options) {
8317
+ const permissions = objectSchema.permissions;
8318
+ if (!options) {
8319
+ options = {};
8320
+ }
8050
8321
 
8051
- operationButtons.push({
8052
- type: 'steedos-object-button',
8053
- name: button.name,
8054
- objectName: button.objectName,
8055
- visibleOn: getButtonVisibleOn(button),
8056
- className: 'antd-Button--default'
8057
- });
8058
- });
8059
- if(operationButtons.length < 1){
8060
- return ;
8061
- }
8062
- return {
8063
- type: 'operation',
8064
- label: '操作',
8065
- fixed: 'right',
8066
- labelClassName: 'text-center',
8067
- className: 'text-center steedos-listview-operation w-20',
8068
- buttons: [
8069
- {
8070
- "type": "steedos-dropdown-button",
8071
- "label": "xxx",
8072
- "buttons": operationButtons,
8073
- "placement": "bottomRight",
8074
- "overlayClassName": "shadow !min-w-[160px]",
8075
- "trigger": ["click"],
8076
- "id": "u:c2140a365019",
8077
- onOpenApi: {
8078
- url: `\${context.rootUrl}/service/api/@\${objectName}/recordPermissions/\${_id}`,
8079
- method: "get",
8080
- data: {
8081
- $: "$$",
8082
- objectName: "${objectName}",
8083
- listViewId: "${listViewId}",
8084
- appId: "${appId}",
8085
- formFactor: "${formFactor}",
8086
- context: `\${context}`
8087
- },
8088
- headers: {
8089
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8090
- },
8091
- adaptor: `
8092
- payload = {
8093
- record: {
8094
- recordPermissions: payload
8095
- }
8096
- };
8097
- return payload;
8098
- `,
8099
- }
8100
- }
8101
- ]
8102
- }
8103
- }
8322
+ calendarOptions = Object.assign({}, DEFAULT_CALENDAR_OPTIONS, omitBy(calendarOptions, isNil));
8104
8323
 
8105
- async function getTableSchema$1(fields, options){
8106
- if(!options){
8107
- options = {};
8108
- }
8109
- let columns = [];
8110
- if(options.formFactor === 'SMALL' || ["split"].indexOf(options.displayAs) > -1){
8111
- columns = await getMobileTableColumns(fields, options);
8324
+ const titleFields = calendarOptions.title || [
8325
+ calendarOptions.startDateExpr,
8326
+ calendarOptions.endDateExpr,
8327
+ calendarOptions.allDayExpr,
8328
+ calendarOptions.textExpr
8329
+ ];
8330
+ let fields = [];
8331
+ each(titleFields, function (n) {
8332
+ if (objectSchema.fields[n]) {
8333
+ fields.push(objectSchema.fields[n]);
8112
8334
  }
8113
- else {
8114
- columns = await getTableColumns(fields, options);
8115
- columns.push(await getTableOperation(options));
8335
+ });
8336
+
8337
+ if (objectSchema.fields[calendarOptions.allDayExpr]) {
8338
+ fields.push(objectSchema.fields[calendarOptions.allDayExpr]);
8339
+ }
8340
+
8341
+ let sort = options.sort;
8342
+ if (!sort) {
8343
+ const sortField = options.sortField;
8344
+ const sortOrder = options.sortOrder;
8345
+ if (sortField) {
8346
+ let sortStr = sortField + ' ' + sortOrder || 'asc';
8347
+ sort = sortStr;
8116
8348
  }
8117
- return {
8118
- mode: "table",
8119
- name: "thelist",
8120
- headerToolbarClassName: "py-2 px-2 border-gray-300 bg-gray-100 border-solid border-b",
8121
- className: "",
8122
- draggable: false,
8123
- defaultParams: getDefaultParams(options),
8124
- columns: columns,
8125
- syncLocation: false,
8126
- keepItemSelectionOnPageChange: true,
8127
- checkOnItemClick: false,
8128
- labelTpl: `\${${options.labelFieldName}}`,
8129
- autoFillHeight: false, // 自动高度效果不理想,先关闭
8130
- columnsTogglable: false,
8349
+ }
8350
+ let initialView = calendarOptions.currentView;
8351
+ if (initialView) {
8352
+ // day, week, month, agenda
8353
+ switch (initialView) {
8354
+ case "day":
8355
+ initialView = "timeGridDay";
8356
+ break;
8357
+ case "week":
8358
+ initialView = "timeGridWeek";
8359
+ break;
8360
+ case "month":
8361
+ initialView = "dayGridMonth";
8362
+ break;
8363
+ case "agenda":
8364
+ initialView = "listWeek";
8365
+ break;
8131
8366
  }
8132
- }
8133
-
8367
+ }
8368
+ else {
8369
+ initialView = "timeGridWeek";
8370
+ }
8134
8371
 
8372
+ options.calendarOptions = calendarOptions;
8373
+ const api = await getCalendarApi(objectSchema, fields, options);
8135
8374
 
8136
- /**
8137
- *
8138
- * @param {*} mainObject
8139
- * @param {*} fields
8140
- * @param {*} options = {filter: listview 过滤条件, ...}
8141
- * @returns
8142
- */
8143
- async function getTableApi(mainObject, fields, options){
8144
- const searchableFields = [];
8145
- let { filter, filtersFunction, sort, top, setDataToComponentId = '' } = options;
8375
+ const onGetEventsScript = `
8376
+ const api = ${JSON.stringify(api)};
8377
+ event.data.calendarOptions = ${JSON.stringify(calendarOptions)};
8378
+ doAction({
8379
+ "actionType": 'ajax',
8380
+ "args": {
8381
+ "api": api
8382
+ },
8383
+ });
8384
+ `;
8146
8385
 
8147
- if(_$1.isArray(filter)){
8148
- filter = _$1.map(filter, function(item){
8149
- if(item.operation){
8150
- return [item.field, item.operation, item.value];
8151
- }else {
8152
- return item
8386
+ const onSelectScript = `
8387
+ const data = event.data;
8388
+ const doc = {};
8389
+ doc["${calendarOptions.startDateExpr}"] = data.start;
8390
+ doc["${calendarOptions.endDateExpr}"] = data.end;
8391
+ doc["${calendarOptions.allDayExpr}"] = data.allDay;
8392
+ doc["${calendarOptions.textExpr}"] = data.title;
8393
+ // ObjectForm会认作用域下的变量值
8394
+ // TODO: 待组件支持initValues属性后应该改掉,不应该通过data直接传值
8395
+ // TODO: 全天事件属性传入doc了但是没有生效,需要手动在ObjectForm中勾选全天事件
8396
+ const title = "新建 ${objectSchema.label}";
8397
+ doAction(
8398
+ {
8399
+ "actionType": "dialog",
8400
+ "dialog": {
8401
+ "type": "dialog",
8402
+ "title": title,
8403
+ "body": [
8404
+ {
8405
+ "type": "steedos-object-form",
8406
+ "objectApiName": "\${objectName}",
8407
+ "mode": "edit",
8408
+ "defaultData": doc,
8409
+ "onEvent": {
8410
+ "submitSucc": {
8411
+ "weight": 0,
8412
+ "actions": [
8413
+ {
8414
+ "actionType": "custom",
8415
+ "script": "event.data.view?.calendar.refetchEvents();"
8416
+ }
8417
+ ]
8418
+ }
8419
+ }
8153
8420
  }
8154
- });
8155
- }
8156
- if(!filter){
8157
- filter = [];
8158
- }
8159
- let baseFilters = null;
8160
- if(filter){
8161
- baseFilters = filter;
8162
- }
8163
- _$1.each(fields,function(field){
8164
- if(field.searchable){
8165
- searchableFields.push(field.name);
8421
+ ],
8422
+ "closeOnEsc": false,
8423
+ "closeOnOutside": false,
8424
+ "showCloseButton": true,
8425
+ "size": "lg"
8166
8426
  }
8167
- });
8427
+ });
8428
+ `;
8168
8429
 
8169
- const fileFields = {};
8170
- const fileFieldsKeys = [];
8171
- // 含有optionsFunction属性, 无reference_to属性的lookup字段
8172
- const lookupFields = {};
8173
- fields.forEach((item)=>{
8174
- if(_$1.includes(['image','avatar','file'], item.type)){
8175
- fileFieldsKeys.push(item.name);
8176
- fileFields[item.name] = {
8177
- name: item.name,
8178
- type: item.type,
8179
- multiple: item.multiple
8180
- };
8181
- }
8182
- if(_$1.includes(['lookup'], item.type) && !item.reference_to ){
8183
- lookupFields[item.name] = item;
8184
- }
8430
+ const onEventClickScript = `
8431
+ const data = event.data;
8432
+ const eventData = data.event;
8433
+ const appId = data.appId;
8434
+ const objectName = data.objectName;
8435
+ const eventId = data.event && data.event.id;
8436
+ doAction({
8437
+ "actionType": "dialog",
8438
+ "dialog": {
8439
+ "type": "dialog",
8440
+ "title": "",
8441
+ "body": [
8442
+ {
8443
+ "type": "steedos-record-detail",
8444
+ "objectApiName": "\${objectName}",
8445
+ "recordId": data.event && data.event.id
8446
+ }
8447
+ ],
8448
+ "closeOnEsc": false,
8449
+ "closeOnOutside": false,
8450
+ "showCloseButton": true,
8451
+ "size": "lg",
8452
+ "actions": []
8453
+ }
8185
8454
  });
8455
+ `;
8186
8456
 
8187
- let valueField = mainObject.key_field || '_id';
8188
- const api = await getApi(mainObject, null, fields, {count: options.queryCount, alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"`});
8457
+ const recordId = "${event.id}";
8458
+ const recordPermissionsApi = getCalendarRecordPermissionsApi(objectSchema, recordId);
8459
+ const recordSaveApi = getCalendarRecordSaveApi(objectSchema, calendarOptions);
8189
8460
 
8190
- if(options.isRelated){
8191
- api.url += "&recordId=${_master.recordId}";
8192
- }
8461
+ const businessHours = {
8462
+ daysOfWeek: [1, 2, 3, 4, 5],
8463
+ startTime: '08:00',
8464
+ endTime: '18:00',
8465
+ };
8466
+ if (!isEmpty(calendarOptions.startDayHour)) {
8467
+ businessHours.startTime = `${calendarOptions.startDayHour}:00`;
8468
+ }
8469
+ if (!isEmpty(calendarOptions.endDayHour)) {
8470
+ businessHours.endTime = `${calendarOptions.endDayHour}:00`;
8471
+ }
8193
8472
 
8194
- api.data.$term = "$term";
8195
- api.data.term = "$term";
8196
- api.data.$self = "$$";
8197
- api.data.self = "$$";
8198
- api.data.filter = "$filter";
8199
- api.data.loaded = "${loaded}";
8200
- api.data.listViewId = "${listViewId}";
8201
- api.data.listName = "${listName}";
8202
- api.requestAdaptor = `
8203
- // selfData 中的数据由 CRUD 控制. selfData中,只能获取到 CRUD 给定的data. 无法从数据链中获取数据.
8204
- let selfData = JSON.parse(JSON.stringify(api.data.$self));
8205
- // 保留一份初始data,以供自定义发送适配器中获取原始数据。
8206
- const data = _.cloneDeep(api.data);
8207
- try{
8208
- // TODO: 不应该直接在这里取localStorage,应该从外面传入
8209
- const listViewId = api.data.listViewId;
8210
- const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
8211
- let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
8212
- if(localListViewProps){
8213
- localListViewProps = JSON.parse(localListViewProps);
8214
- selfData = Object.assign({}, localListViewProps, selfData);
8215
- if(!api.data.filter){
8216
- api.data.filter = localListViewProps.filter;
8217
- }
8218
- if(!api.data.loaded){
8219
- // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
8220
- // 所以会把localSearchableFilter中已经存过的页码覆盖
8221
- // 如果是第一次加载组件始终让翻页页码从本地存储中取值
8222
- let formFactor = "${options.formFactor}";
8223
- // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
8224
- api.data.pageNo = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
8225
- }
8226
- }
8227
- }
8228
- catch(ex){
8229
- console.error("本地存储中crud参数解析异常:", ex);
8230
- }
8231
- ${baseFilters ? `var systemFilters = ${JSON.stringify(baseFilters)};` : 'var systemFilters = [];'}
8232
- var _ids = []
8233
- const filtersFunction = ${filtersFunction};
8234
- if(filtersFunction){
8235
- const _filters = filtersFunction(systemFilters, api.data.$self);
8236
- if(api.data.listName == "recent"){
8237
- _ids = _filters[2]
8238
- }
8239
- if(_filters && _filters.length > 0){
8240
- if(_.isEmpty(systemFilters)){
8241
- systemFilters = _filters || [];
8242
- }else{
8243
- systemFilters = [systemFilters, 'and', _filters];
8244
- }
8245
- }
8246
- }
8247
- let userFilters =[];
8248
-
8249
- if(_.isEmpty(systemFilters)){
8250
- systemFilters = api.data.filter || [];
8251
- }else{
8252
- if(!_.isEmpty(api.data.filter)){
8253
- systemFilters = [systemFilters, 'and', api.data.filter];
8254
- }
8255
- }
8256
- var pageSize = api.data.pageSize || 10;
8257
- var pageNo = api.data.pageNo || 1;
8258
- var skip = (pageNo - 1) * pageSize;
8259
- var orderBy = api.data.orderBy || '';
8260
- var orderDir = api.data.orderDir || '';
8261
- var sort = orderBy + ' ' + orderDir;
8262
- sort = orderBy ? sort : "${sort || ''}";
8263
- var allowSearchFields = ${JSON.stringify(searchableFields)};
8264
- if(api.data.$term){
8265
- userFilters = [["name", "contains", "'+ api.data.$term +'"]];
8266
- }else if(selfData.op === 'loadOptions' && selfData.value){
8267
- userFilters = [["${valueField.name}", "=", selfData.value]];
8473
+ const onEvent = {
8474
+ "getEvents": {
8475
+ "weight": 0,
8476
+ "actions": [
8477
+ {
8478
+ "componentId": "",
8479
+ "args": {
8480
+ },
8481
+ "actionType": "custom",
8482
+ "script": onGetEventsScript
8268
8483
  }
8269
-
8270
- var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
8271
-
8272
- if(searchableFilter.length > 0){
8273
- if(userFilters.length > 0 ){
8274
- userFilters = [userFilters, 'and', searchableFilter];
8275
- }else{
8276
- userFilters = searchableFilter;
8277
- }
8484
+ ]
8485
+ },
8486
+ "select": {
8487
+ "weight": 0,
8488
+ "actions": [
8489
+ {
8490
+ "componentId": "",
8491
+ "args": {
8492
+ },
8493
+ "actionType": "custom",
8494
+ "script": onSelectScript
8278
8495
  }
8279
-
8280
- if(allowSearchFields){
8281
- allowSearchFields.forEach(function(key){
8282
- const keyValue = selfData[key];
8283
- if(_.isString(keyValue)){
8284
- userFilters.push([key, "contains", keyValue]);
8285
- }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8286
- userFilters.push([key, "=", keyValue]);
8287
- }
8288
- })
8496
+ ]
8497
+ },
8498
+ "eventClick": {
8499
+ "weight": 0,
8500
+ "actions": [
8501
+ {
8502
+ "componentId": "",
8503
+ "args": {
8504
+ },
8505
+ "actionType": "custom",
8506
+ "script": onEventClickScript
8289
8507
  }
8290
-
8291
- if(selfData.__keywords && allowSearchFields){
8292
- const keywordsFilters = [];
8293
- allowSearchFields.forEach(function(key, index){
8294
- const keyValue = selfData.__keywords;
8295
- if(keyValue){
8296
- keywordsFilters.push([key, "contains", keyValue]);
8297
- if(index < allowSearchFields.length - 1){
8298
- keywordsFilters.push('or');
8299
- }
8300
- }
8301
- })
8302
- userFilters.push(keywordsFilters);
8303
- };
8304
-
8305
- let filters = [];
8306
-
8307
- if(!_.isEmpty(systemFilters)){
8308
- filters = systemFilters;
8309
- };
8310
- if(api.data.$self.additionalFilters){
8311
- if(_.isString(api.data.$self.additionalFilters)){
8312
- userFilters.push(eval(api.data.$self.additionalFilters))
8313
- }else{
8314
- userFilters.push(api.data.$self.additionalFilters)
8315
- }
8508
+ ]
8509
+ },
8510
+ "eventAdd": {
8511
+ "weight": 0,
8512
+ "actions": [
8513
+ {
8514
+ "componentId": "",
8515
+ "args": {
8516
+ },
8517
+ "actionType": "custom",
8518
+ "script": "console.log('eventAdd'); console.log(event);"
8316
8519
  }
8317
-
8318
- if(api.data.$self._isRelated){
8319
- const self = api.data.$self;
8320
- const relatedKey = self.relatedKey;
8321
- const refField = self.uiSchema.fields[relatedKey];
8322
- const masterRecord = self._master.record;
8323
- const masterObjectName = self._master.objectName;
8324
- let relatedValue = self._master.recordId;
8325
- if(refField.reference_to_field && refField.reference_to_field != '_id'){
8326
- relatedValue = masterRecord[refField.reference_to_field]
8327
- }
8328
- let relatedFilters;
8329
- if (
8330
- refField._reference_to ||
8331
- (refField.reference_to && !_.isString(refField.reference_to))
8332
- ) {
8333
- relatedFilters = [
8334
- [relatedKey + "/o", "=", masterObjectName],
8335
- [relatedKey + "/ids", "=", relatedValue],
8336
- ];
8337
- } else {
8338
- relatedFilters = [relatedKey, "=", relatedValue];
8520
+ ]
8521
+ },
8522
+ "eventChange": {
8523
+ "weight": 0,
8524
+ "actions": [
8525
+ {
8526
+ "actionType": 'ajax',
8527
+ "args": {
8528
+ "api": recordPermissionsApi
8529
+ }
8530
+ },
8531
+ {
8532
+ "actionType": "toast",
8533
+ "expression": "!event.data.editable",
8534
+ "args": {
8535
+ "msgType": "error",
8536
+ "msg": "您没有编辑该记录的权限!",
8537
+ "position": "top-center"
8538
+ }
8539
+ },
8540
+ {
8541
+ "actionType": 'ajax',
8542
+ "expression": "event.data.editable",
8543
+ "args": {
8544
+ "api": recordSaveApi,
8545
+ "messages": {
8546
+ "success": objectSchema.label + "修改成功",
8547
+ "failed": objectSchema.label + "修改失败!"
8339
8548
  }
8340
- userFilters.push(relatedFilters)
8549
+ }
8341
8550
  }
8342
-
8343
- if(!_.isEmpty(userFilters)){
8344
- if(_.isEmpty(filters)){
8345
- filters = userFilters;
8346
- }else{
8347
- filters = [filters, 'and', userFilters]
8348
- }
8551
+ ]
8552
+ },
8553
+ "eventRemove": {
8554
+ "weight": 0,
8555
+ "actions": [
8556
+ {
8557
+ "componentId": "",
8558
+ "args": {
8559
+ },
8560
+ "actionType": "custom",
8561
+ "script": "console.log('eventRemove'); console.log(event);"
8349
8562
  }
8350
- api.data._ids = _ids;
8351
- api.data = {
8352
- query: api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim())
8563
+ ]
8564
+ },
8565
+ "eventsSet": {
8566
+ "weight": 0,
8567
+ "actions": [
8568
+ {
8569
+ "componentId": "",
8570
+ "args": {
8571
+ },
8572
+ "actionType": "custom",
8573
+ "script": "console.log('eventsSet'); console.log(event);"
8353
8574
  }
8354
- ${options.requestAdaptor || ''}
8355
- return api;
8356
- `;
8357
- api.adaptor = `
8358
- if(api.body.listName == "recent"){
8359
- payload.data.rows = _.sortBy(payload.data.rows, function(item){
8360
- return _.indexOf(api.body._ids, item._id)
8361
- });
8362
- }
8363
- const enable_tree = ${mainObject.enable_tree};
8364
- if(!enable_tree){
8365
- _.each(payload.data.rows, function(item, index){
8366
- const {pageNo, pageSize} = api.body;
8367
- const skip = (pageNo - 1) * pageSize;
8368
- item._index = skip + index + 1;
8369
- })
8370
- }
8371
- window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8372
- let fileFields = ${JSON.stringify(fileFields)};
8373
- let lookupFields = ${JSON.stringify(lookupFields)};
8374
- _.each(payload.data.rows, function(item, index){
8375
- _.each(fileFields , (field, key)=>{
8376
- if(item[key] && item._display && item._display[key]){
8377
- let value = item._display[key];
8378
- if(!_.isArray(value)){
8379
- value = [value]
8380
- };
8381
- if(field.type === 'file'){
8382
- item[key] = value
8383
- }else{
8384
- item[key] = _.map(value, 'url')
8385
- }
8386
- }
8387
- })
8388
- _.each(lookupFields , (field, key)=>{
8389
- if(item[key]){
8390
- if(field._optionsFunction){
8391
- const optionsFunction = eval("(" + field._optionsFunction+ ")")(item);
8392
- item[key + '__label'] = _.map(_.filter(optionsFunction, function(option){return _.includes(item[key], option.value)}), 'label').join(' ');
8393
- }
8394
- }
8395
- })
8396
- })
8397
-
8398
- if(enable_tree){
8399
- const records = payload.data.rows || [];
8400
- const getTreeOptions = SteedosUI.getTreeOptions
8401
- payload.data.rows = getTreeOptions(records,{"valueField":"_id"});
8575
+ ]
8402
8576
  }
8577
+ };
8403
8578
 
8579
+ Object.assign(onEvent, options.onEvent);
8404
8580
 
8405
- try{
8406
- // TODO: 不应该直接在这里取localStorage,应该从外面传入
8407
- const listViewId = api.body.listViewId;
8408
- const listViewPropsStoreKey = location.pathname + "/crud/" + listViewId ;
8409
- /**
8410
- * localListViewProps规范来自crud请求api中api.data.$self参数值的。
8411
- * 比如:{"perPage":20,"page":1,"__searchable__name":"7","__searchable__between__n1__c":[null,null],"filter":[["name","contains","a"]]}
8412
- * __searchable__...:顶部放大镜搜索条件
8413
- * filter:右侧过滤器
8414
- * perPage:每页条数
8415
- * page:当前页码
8416
- * orderBy:排序字段
8417
- * orderDir:排序方向
8418
- */
8419
- let localListViewProps = sessionStorage.getItem(listViewPropsStoreKey);
8420
- let selfData = JSON.parse(JSON.stringify(api.body.$self));
8421
- if(localListViewProps){
8422
- localListViewProps = JSON.parse(localListViewProps);
8423
- selfData = Object.assign({}, localListViewProps, selfData, { filter: api.body.filter });
8424
- if(!api.body.loaded){
8425
- // 第一次加载组件,比如刷新浏览器时因为api.data.pageNo有默认值1
8426
- // 所以会把localSearchableFilter中已经存过的页码覆盖
8427
- // 如果是第一次加载组件始终让翻页页码从本地存储中取值
8428
- let formFactor = "${options.formFactor}";
8429
- // 移动端不识别本地存储中的翻页页码,否则点击加载更多按钮后无法刷新回第一页
8430
- selfData.page = formFactor === "SMALL" ? 1 : (localListViewProps.page || 1);
8431
- }
8432
- }
8433
- delete selfData.context;
8434
- delete selfData.global;
8435
- sessionStorage.setItem(listViewPropsStoreKey, JSON.stringify(selfData));
8436
- // 返回页码到UI界面
8437
- payload.data.page= selfData.page;
8581
+ const config = options.config || {};
8582
+ if(config.eventContent && typeof config.eventContent === "string"){
8583
+ const hasReturn = /\breturn\b/.test(config.eventContent);
8584
+ if(hasReturn){
8585
+ try {
8586
+ // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8587
+ let fn = new Function("arg", config.eventContent);
8588
+ config.eventContent = fn;
8589
+ } catch (e) {
8590
+ console.warn(e);
8591
+ }
8438
8592
  }
8439
- catch(ex){
8440
- console.error("本地存储中crud参数解析异常:", ex);
8593
+ }
8594
+
8595
+ if(config.noEventsContent && typeof config.noEventsContent === "string"){
8596
+ const hasReturn = /\breturn\b/.test(config.noEventsContent);
8597
+ if(hasReturn){
8598
+ try {
8599
+ // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8600
+ let fn = new Function("arg", config.noEventsContent);
8601
+ config.noEventsContent = fn;
8602
+ } catch (e) {
8603
+ console.warn(e);
8604
+ }
8441
8605
  }
8442
- // 标记加载过,后续优先从本地存储中加载相关参数
8443
- payload.data.loaded= true;
8606
+ }
8444
8607
 
8445
- const setDataToComponentId = "${setDataToComponentId}";
8446
- if(setDataToComponentId){
8447
- SteedosUI.getRef(api.body.$self.$scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8448
- };
8449
- ${options.adaptor || ''}
8450
- return payload;
8451
- `;
8452
- return api;
8608
+ const amisSchema = {
8609
+ "type": "steedos-fullcalendar",
8610
+ "label": "",
8611
+ "name": "fullcalendar",
8612
+ "placeholder":"${additionalFilters}",//用于触发reload
8613
+ "editable": permissions.allowEdit,
8614
+ "selectable": permissions.allowCreate,
8615
+ "selectMirror": permissions.allowCreate,
8616
+ "initialView": initialView,
8617
+ "businessHours": businessHours,
8618
+ ...config,
8619
+ "onEvent": onEvent
8620
+ };
8621
+ return amisSchema;
8453
8622
  }
8454
8623
 
8455
- async function getApi(object, recordId, fields, options){
8456
- const data = await getFindQuery(object, recordId, fields, options);
8457
- return {
8458
- method: "post",
8459
- url: getApi$2(), // + "&recordId=${recordId}"
8460
- data: data,
8461
- headers: {
8462
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8463
- }
8464
- }
8465
- }
8624
+ /*
8625
+ * @Author: baozhoutao@steedos.com
8626
+ * @Date: 2022-05-26 16:02:08
8627
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
8628
+ * @LastEditTime: 2023-06-04 15:49:23
8629
+ * @Description:
8630
+ */
8466
8631
 
8467
- function getRecordPermissionsApi(object, recordId, options){
8468
- const data = getRecordPermissionsQuery(object, recordId, options);
8469
- return {
8470
- method: "post",
8471
- url: getApi$2(),
8472
- data: data,
8473
- headers: {
8474
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8475
- }
8632
+ const getFieldSchemaArray = (formFields) => {
8633
+ let fieldSchemaArray = [];
8634
+ fieldSchemaArray.length = 0;
8635
+
8636
+ _$1.forEach(formFields, (field) => {
8637
+ if (!field.group || field.group == 'null' || field.group == '-')
8638
+ field.group = '通用';
8639
+ const fieldName = field.name;
8640
+ let isObjectField = /\w+\.\w+/.test(fieldName);
8641
+ if (field.type == 'grid' || field.type == 'object') {
8642
+ // field.group = field.label
8643
+ field.is_wide = true;
8476
8644
  }
8477
- }
8478
8645
 
8479
- const DEFAULT_CALENDAR_OPTIONS = {
8480
- startDateExpr: "start",
8481
- endDateExpr: "end",
8482
- allDayExpr: "is_all_day",
8483
- textExpr: "name"
8646
+ if (!isObjectField) {
8647
+ if (!field.hidden) {
8648
+ fieldSchemaArray.push(Object.assign({ name: fieldName }, field, { permission: { allowEdit: true } }));
8649
+ }
8650
+ }
8651
+ });
8652
+ return fieldSchemaArray;
8484
8653
  };
8485
8654
 
8486
- async function getCalendarApi(mainObject, fields, options) {
8487
- if (!options) {
8488
- options = {};
8655
+ const getSection = async (formFields, permissionFields, fieldSchemaArray, sectionName, ctx) => {
8656
+ if (!ctx) {
8657
+ ctx = {};
8489
8658
  }
8490
- const calendarOptions = options.calendarOptions;
8491
- const searchableFields = [];
8492
- let { filter, sort, top, setDataToComponentId = '' } = options;
8493
-
8494
- if (!top) {
8495
- // 日历请求不翻页
8496
- top = 200;
8659
+ const sectionFields = _$1.filter(fieldSchemaArray, { 'group': sectionName });
8660
+ if (sectionFields.length == _$1.filter(sectionFields, ['hidden', true]).length) {
8661
+ return;
8497
8662
  }
8498
8663
 
8499
- if (___default.isArray(filter)) {
8500
- filter = ___default.map(filter, function (item) {
8501
- if (item.operation) {
8502
- return [item.field, item.operation, item.value];
8503
- } else {
8504
- return item
8664
+ const fieldSetBody = [];
8665
+
8666
+ for (const perField of sectionFields) {
8667
+ let field = perField;
8668
+ if (perField.type === 'grid') {
8669
+ field = await getGridFieldSubFields(perField, formFields);
8670
+ // console.log(`perField.type grid ===> field`, field)
8671
+ } else if (perField.type === 'object') {
8672
+ field = await getObjectFieldSubFields(perField, formFields);
8673
+ // console.log(`perField.type object ===> field`, field)
8674
+ }
8675
+ if (field.name.indexOf(".") < 0) {
8676
+ ctx.__formFields = formFields;
8677
+ const amisField = await convertSFieldToAmisField(field, field.readonly, ctx);
8678
+ // console.log(`${field.name} amisField`, field, amisField)
8679
+ if (amisField) {
8680
+ fieldSetBody.push(amisField);
8505
8681
  }
8506
- });
8682
+ }
8507
8683
  }
8508
- if (!filter) {
8509
- filter = [];
8684
+
8685
+ // fieldSet 已支持显隐控制
8686
+ const sectionFieldsVisibleOn = _$1.map(_$1.compact(_$1.map(fieldSetBody, 'visibleOn')), (visibleOn) => {
8687
+ return visibleOn;
8688
+ });
8689
+
8690
+ let section = {
8691
+ "type": "fieldSet",
8692
+ "title": sectionName,
8693
+ "collapsable": true,
8694
+ "body": fieldSetBody,
8695
+ };
8696
+
8697
+ if (ctx.enableTabs) {
8698
+ section = {
8699
+ "title": sectionName,
8700
+ "body": fieldSetBody,
8701
+ };
8510
8702
  }
8511
8703
 
8512
- ___default.each(fields, function (field) {
8513
- if (field.searchable) {
8514
- searchableFields.push(field.name);
8704
+ if (sectionFieldsVisibleOn.length > 0 && fieldSetBody.length === sectionFieldsVisibleOn.length) {
8705
+ section.visibleOn = `${sectionFieldsVisibleOn.join(" || ")}`;
8706
+ }
8707
+ return section
8708
+ };
8709
+
8710
+ const getSections = async (permissionFields, formFields, ctx) => {
8711
+ if (!ctx) {
8712
+ ctx = {};
8713
+ }
8714
+ const fieldSchemaArray = getFieldSchemaArray(formFields);
8715
+ const _sections = _$1.groupBy(fieldSchemaArray, 'group');
8716
+ const sections = [];
8717
+ var sectionVisibleOns = [];
8718
+ for (const key in _sections) {
8719
+ const section = await getSection(formFields, permissionFields, fieldSchemaArray, key, ctx);
8720
+ if (section.body.length > 0) {
8721
+ if (section.visibleOn) {
8722
+ sectionVisibleOns.push(section.visibleOn);
8723
+ }
8724
+ else {
8725
+ sectionVisibleOns.push("true");
8726
+ }
8727
+ sections.push(section);
8515
8728
  }
8729
+ }
8730
+ /*
8731
+ 为了实现只有一个分组时隐藏该分组标题,需要分三种情况(分组如果没有visibleon属性就代表一定显示,有visibleon需要进行判断)
8732
+ 1 当前分组为隐藏时,标题就设置为隐藏
8733
+ 2 当前分组为显示时,其他分组只要有一个是显示,就显示该分组标题
8734
+ 3 当前分组为显示时,其他分组都隐藏,就隐藏该分组标题
8735
+ */
8736
+ sections.forEach((section, index) => {
8737
+ var tempSectionVisibleOns = sectionVisibleOns.slice();
8738
+ tempSectionVisibleOns.splice(index, 1);
8739
+ section.headingClassName = {
8740
+ "hidden": `!((${tempSectionVisibleOns.join(" || ") || 'false'}) && ${sectionVisibleOns[index]})`
8741
+ };
8516
8742
  });
8517
8743
 
8518
- const idFieldName = mainObject.idFieldName || "_id";
8519
- let valueField = mainObject.key_field || '_id';
8520
- const api = await getApi(mainObject, null, fields, { alias: 'rows', limit: top, queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"` });
8521
- api.data.$term = "$term";
8522
- api.data.$self = "$$";
8523
- api.data.filter = "$filter";
8524
- api.data.pageSize = top || 10;
8525
- api.requestAdaptor = `
8526
- let selfData = JSON.parse(JSON.stringify(api.data.$self));
8527
- var filters = api.data.filter || ${JSON.stringify(filter)} || [];
8528
- const eventFetchInfo = selfData.fetchInfo;
8529
- const startDateExpr = "${calendarOptions.startDateExpr}";
8530
- const endDateExpr = "${calendarOptions.endDateExpr}";
8531
- const eventDurationFilters = [[endDateExpr, ">=", eventFetchInfo.start], [startDateExpr, "<=", eventFetchInfo.end]];
8532
- if(_.isEmpty(filters)){
8533
- filters = eventDurationFilters;
8534
- }else{
8535
- filters = [filters, 'and', eventDurationFilters]
8536
- }
8744
+ if (ctx.enableTabs) {
8745
+ // TODO: 以下sectionHeaderVisibleOn代码逻辑是为实现只有一个选项卡时给选项卡添加sectionHeaderVisibleOn样式类来把选项卡顶部卡头隐藏
8746
+ // 但是 amis filter过滤器有两个bug造成此功能不好实现:
8747
+ // 1.filter过滤器只支持对象数组,并不支持boolean或字符串数组,见: https://github.com/baidu/amis/issues/7078
8748
+ // 2.filter过滤器的返回结果无法进一步获取最终过滤后的数组长度,见:https://github.com/baidu/amis/issues/7077
8749
+ // let sectionHeaderVisibleOn = "false";
8750
+ // if(sectionVisibleOns.length){
8751
+ // sectionHeaderVisibleOn = "[" + sectionVisibleOns.join(",") + "]" + "|filter:equals:true.length > 1";
8752
+ // }
8753
+ // console.log("===sectionHeaderVisibleOn===", sectionHeaderVisibleOn);
8754
+ // sectionHeaderVisibleOn = "[true]|filter:equals:true.length > 1";
8755
+ // sectionHeaderVisibleOn = "false";
8756
+ // sectionHeaderVisibleOn = "[1,1,1]|filter:equals:1.length > 1";
8757
+ return [
8758
+ {
8759
+ "type": "tabs",
8760
+ // "className": {
8761
+ // "hiddenFormTabs": `!(${sectionHeaderVisibleOn})`
8762
+ // },
8763
+ "tabs": sections,
8764
+ "tabsMode": ctx.tabsMode
8765
+ }
8766
+ ]
8767
+ }
8768
+
8769
+ return sections;
8770
+ };
8771
+
8772
+ /*
8773
+ * @Author: baozhoutao@steedos.com
8774
+ * @Date: 2022-07-07 11:02:29
8775
+ * @LastEditors: baozhoutao@steedos.com
8776
+ * @LastEditTime: 2023-03-07 17:19:34
8777
+ * @Description:
8778
+ */
8779
+
8780
+ async function getFormBody(permissionFields, formFields, ctx){
8781
+ return await getSections(permissionFields, formFields, ctx);
8782
+ }
8783
+
8784
+ // lodash的defaultsDeep函数有bug,无法正确合并值为数值的节点,重写修正该函数
8785
+ // 源码出处:https://github.com/nodeutils/defaults-deep
8786
+ const defaultsDeep = (...args)=>{
8787
+ let output = {};
8788
+ toArray(args).reverse().forEach(item=> {
8789
+ mergeWith(output, item, (objectValue, sourceValue) => {
8790
+ return isArray(sourceValue) ? sourceValue : undefined;
8791
+ });
8792
+ });
8793
+ return output;
8794
+ };
8795
+
8796
+ function getBulkActions(objectSchema){
8797
+ return [
8798
+ {
8799
+ "type": "button",
8800
+ "level": "danger",
8801
+ "label": "批量删除",
8802
+ "actionType": "ajax",
8803
+ "confirmText": "确定要删除吗",
8804
+ "className": "hidden",
8805
+ "id": "batchDelete",
8806
+ "api": getBatchDelete(objectSchema.name),
8807
+ }
8808
+ // {
8809
+ // "label": "批量修改",
8810
+ // "actionType": "dialog",
8811
+ // "dialog": {
8812
+ // "title": "批量编辑",
8813
+ // "name": "sample-bulk-edit",
8814
+ // "body": {
8815
+ // "type": "form",
8816
+ // "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/sample/bulkUpdate2",
8817
+ // "controls": [
8818
+ // {
8819
+ // "type": "hidden",
8820
+ // "name": "ids"
8821
+ // },
8822
+ // {
8823
+ // "type": "text",
8824
+ // "name": "name",
8825
+ // "label": "Name"
8826
+ // }
8827
+ // ]
8828
+ // }
8829
+ // }
8830
+ // }
8831
+ ]
8832
+ }
8537
8833
 
8538
- if(api.data.$self.additionalFilters){
8539
- filters.push(api.data.$self.additionalFilters)
8834
+ async function getObjectCRUD(objectSchema, fields, options){
8835
+ // console.time('getObjectCRUD');
8836
+ const { top, perPage, showDisplayAs = false, displayAs, crudClassName = "" } = options;
8837
+ const nonpaged = objectSchema.paging && objectSchema.paging.enabled === false;
8838
+ const isTreeObject = objectSchema.enable_tree;
8839
+ const bulkActions = getBulkActions(objectSchema);
8840
+ const bodyProps = {
8841
+ // toolbar: getToolbar(),
8842
+ // headerToolbar: getObjectHeaderToolbar(objectSchema, options.formFactor, {showDisplayAs}),
8843
+ headerToolbarClassName: "px-4 py-2 border-gray-300 bg-gray-100 border-solid border-b",
8844
+ footerToolbar: getObjectFooterToolbar(objectSchema, options.formFactor, {
8845
+ disableStatistics: options.queryCount === false
8846
+ }),
8847
+ filter: options.filterVisible !== false && await getObjectFilter(objectSchema, fields, options),
8848
+ };
8849
+ if(options.formFactor !== 'SMALL' || ["split"].indexOf(options.displayAs) == -1){
8850
+ Object.assign(bodyProps, {
8851
+ bulkActions: options.bulkActions != false ? bulkActions : false
8852
+ });
8540
8853
  }
8541
-
8542
- var pageSize = api.data.pageSize || 10;
8543
- var pageNo = api.data.pageNo || 1;
8544
- var skip = (pageNo - 1) * pageSize;
8545
- var orderBy = api.data.orderBy || '';
8546
- var orderDir = api.data.orderDir || '';
8547
- var sort = orderBy + ' ' + orderDir;
8548
- sort = orderBy ? sort : "${sort}";
8549
- var allowSearchFields = ${JSON.stringify(searchableFields)};
8550
- if(api.data.$term){
8551
- filters = [["name", "contains", "'+ api.data.$term +'"]];
8552
- }else if(selfData.op === 'loadOptions' && selfData.value){
8553
- filters = [["${valueField.name}", "=", selfData.value]];
8854
+ // yml里配置的 不分页和enable_tree:true 优先级最高,组件中输入的top次之。
8855
+ options.queryCount = true;
8856
+ if(nonpaged || isTreeObject){
8857
+ options.top = 5000;
8858
+ bodyProps.footerToolbar = [];
8859
+ options.queryCount = true; // 禁止翻页的时候, 需要查找总数
8860
+ }else if(top){
8861
+ bodyProps.footerToolbar = [];
8862
+ if(options.isRelated){
8863
+ options.queryCount = true;
8864
+ }else {
8865
+ options.queryCount = false;
8866
+ }
8554
8867
  }
8555
- var searchableFilter = SteedosUI.getSearchFilter(selfData) || [];
8868
+ // console.log(`getObjectHeaderToolbar====2===>`, options.filterVisible)
8869
+ bodyProps.headerToolbar = getObjectHeaderToolbar(objectSchema, options.formFactor, {
8870
+ showDisplayAs,
8871
+ hiddenCount: options.queryCount === false,
8872
+ headerToolbarItems: options.headerToolbarItems,
8873
+ filterVisible: options.filterVisible
8874
+ });
8556
8875
 
8557
- if(searchableFilter.length > 0){
8558
- if(filters.length > 0 ){
8559
- filters = [filters, 'and', searchableFilter];
8560
- }else{
8561
- filters = searchableFilter;
8562
- }
8563
- }
8564
8876
 
8565
- if(allowSearchFields){
8566
- allowSearchFields.forEach(function(key){
8567
- const keyValue = selfData[key];
8568
- if(_.isString(keyValue)){
8569
- filters.push([key, "contains", keyValue]);
8570
- }else if(_.isArray(keyValue) || _.isBoolean(keyValue) || keyValue){
8571
- filters.push([key, "=", keyValue]);
8877
+ let body = null;
8878
+ const id = `listview_${objectSchema.name}`;
8879
+ if(options.formFactor === 'SMALL' && false){
8880
+ delete bodyProps.bulkActions;
8881
+ delete bodyProps.headerToolbar;
8882
+ delete bodyProps.footerToolbar;
8883
+ const card = await getCardSchema(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: objectSchema.NAME_FIELD_KEY || 'name'}, options, {actions: false}));
8884
+ body = Object.assign({}, card , {
8885
+ type: 'crud',
8886
+ primaryField: '_id',
8887
+ id: id,
8888
+ name: id,
8889
+ keepItemSelectionOnPageChange: false,
8890
+ api: await getTableApi(objectSchema, fields, options),
8891
+ hiddenOn: options.tableHiddenOn,
8892
+ },
8893
+ bodyProps
8894
+ );
8895
+ }else {
8896
+ let labelFieldName = objectSchema.NAME_FIELD_KEY || 'name';
8897
+ // organizations 对象的历史遗留问题, fullname 被标记为了 名称字段. 在此处特殊处理.
8898
+ if(objectSchema.name === 'organizations'){
8899
+ labelFieldName = 'name';
8900
+ }
8901
+ const table = await getTableSchema$1(fields, Object.assign({idFieldName: objectSchema.idFieldName, labelFieldName: labelFieldName, permissions:objectSchema.permissions,enable_inline_edit:objectSchema.enable_inline_edit}, options));
8902
+ delete table.mode;
8903
+ //image与avatar需要在提交修改时特别处理
8904
+ const imageNames = ___default.compact(___default.map(___default.filter(fields, (field) => ["image","avatar"].includes(field.type)), 'name'));
8905
+ const quickSaveApiRequestAdaptor = `
8906
+ var graphqlOrder = "";
8907
+ var imageNames = ${JSON.stringify(imageNames)};
8908
+ api.data.rowsDiff.forEach(function (item, index) {
8909
+ for(key in item){
8910
+ if(_.includes(imageNames, key)){
8911
+ if(typeof item[key] == "string"){
8912
+ const match = item[key].match(/\\/([^\\/]+)$/);
8913
+ item[key] = match && match.length > 1?match[1]:"";
8914
+ }else{
8915
+ item[key] = _.map(item[key], function(ele){
8916
+ const match = ele.match(/\\/([^\\/]+)$/);
8917
+ return match && match.length > 1?match[1]:"";
8918
+ })
8919
+ }
8572
8920
  }
8921
+ }
8922
+ const itemOrder = 'update' + index + ':' + api.data.objectName + '__update(id:"' + item._id + '", doc:' + JSON.stringify(JSON.stringify(_.omit(item, '_id'))) + ') {_id}';
8923
+ graphqlOrder += itemOrder;
8573
8924
  })
8574
- }
8575
-
8576
- if(selfData.__keywords && allowSearchFields){
8577
- const keywordsFilters = [];
8578
- allowSearchFields.forEach(function(key, index){
8579
- const keyValue = selfData.__keywords;
8580
- if(keyValue){
8581
- keywordsFilters.push([key, "contains", keyValue]);
8582
- if(index < allowSearchFields.length - 1){
8583
- keywordsFilters.push('or');
8584
- }
8925
+ graphqlOrder = 'mutation {' + graphqlOrder + '}';
8926
+ return {
8927
+ ...api,
8928
+ data: {
8929
+ query: graphqlOrder
8585
8930
  }
8586
- })
8587
- filters.push(keywordsFilters);
8588
- }
8589
- api.data.query = api.data.query.replace(/{__filters}/g, JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim());
8590
- delete api.data.$term;
8591
- delete api.data.filter;
8592
- delete api.data.pageSize;
8593
- delete api.data.pageNo;
8594
- delete api.data.orderBy;
8595
- delete api.data.orderDir;
8596
- return api;
8597
- `;
8598
- api.adaptor = `
8599
- window.postMessage(Object.assign({type: "listview.loaded"}), "*");
8600
- const setDataToComponentId = "${setDataToComponentId}";
8601
- if(setDataToComponentId){
8602
- SteedosUI.getRef(api.body.$self.scopeId)?.getComponentById(setDataToComponentId)?.setData({$count: payload.data.count})
8603
- }
8604
- const rows = payload.data.rows || [];
8605
- const selfData = api.data.$self;
8606
- const events = rows.map(function(n){
8607
- return {
8608
- id: n["${idFieldName}"],
8609
- title: n["${calendarOptions.textExpr}"],
8610
- start: n["${calendarOptions.startDateExpr}"],
8611
- end: n["${calendarOptions.endDateExpr}"],
8612
- allDay: n["${calendarOptions.allDayExpr}"],
8613
- extendedProps: n
8614
- }
8615
- });
8616
- const successCallback = selfData.successCallback;
8617
- const failureCallback = selfData.failureCallback;
8618
- successCallback(events);
8619
- return payload;
8620
- `;
8621
- return api;
8622
- }
8931
+ }
8932
+ `;
8623
8933
 
8624
- function getCalendarRecordPermissionsApi(mainObject, recordId) {
8625
- const api = getRecordPermissionsApi(mainObject, recordId, { alias: 'rows', limit: 1, fields: ["allowEdit"] });
8626
- api.data.$self = "$$";
8627
- api.adaptor = `
8628
- const rows = payload.data.rows || [];
8629
- const selfData = api.data.$self;
8630
- const revert = selfData.revert;
8631
- const recordPermissions = rows[0] && rows[0].recordPermissions;
8632
- const editable = !!(recordPermissions && recordPermissions.allowEdit);
8633
- if(!editable){
8634
- // 没有权限时还原
8635
- revert && revert();
8934
+ body = Object.assign({}, table, {
8935
+ type: 'crud',
8936
+ primaryField: '_id',
8937
+ affixHeader: false,
8938
+ id: id,
8939
+ name: id,
8940
+ keepItemSelectionOnPageChange: true,
8941
+ api: await getTableApi(objectSchema, fields, options),
8942
+ hiddenOn: options.tableHiddenOn,
8943
+ autoFillHeight: options.isRelated ? false : true,
8944
+ className: `flex-auto ${crudClassName || ""}`,
8945
+ bodyClassName: "bg-white",
8946
+ crudClassName: crudClassName,
8947
+ quickSaveApi: {
8948
+ url: `\${context.rootUrl}/graphql`,
8949
+ method: "post",
8950
+ dataType: "json",
8951
+ headers: {
8952
+ Authorization: "Bearer ${context.tenantId},${context.authToken}",
8953
+ },
8954
+ requestAdaptor: quickSaveApiRequestAdaptor,
8955
+ },
8956
+ rowClassNameExpr: options.rowClassNameExpr
8957
+ },
8958
+ bodyProps,
8959
+ );
8636
8960
  }
8637
- payload.data.editable = editable;
8638
- return payload;
8639
- `;
8640
- return api;
8641
- }
8642
-
8643
- function getCalendarRecordSaveApi(object, calendarOptions) {
8644
- const formData = {};
8645
- const idFieldName = object.idFieldName || "_id";
8646
- formData[idFieldName] = "${event.data.event.id}";
8647
- const nameFieldKey = object.NAME_FIELD_KEY || "name";
8648
- formData[nameFieldKey] = "${event.data.event.title}";
8649
- formData[calendarOptions.startDateExpr] = "${event.data.event.start}";
8650
- formData[calendarOptions.endDateExpr] = "${event.data.event.end}";
8651
- formData[calendarOptions.allDayExpr] = "${event.data.event.allDay}";
8652
- // formData[calendarOptions.textExpr] = "${event.data.event.title}";
8653
- const apiData = {
8654
- objectName: "${objectName}",
8655
- $: formData,
8656
- $self: "$$"
8657
- };
8658
- const saveDataTpl = `
8659
- const formData = api.data.$;
8660
- const objectName = api.data.objectName;
8661
- let query = \`mutation{record: \${objectName}__update(id: "\${formData.${idFieldName}}", doc: {__saveData}){${idFieldName}}}\`;
8662
- delete formData.${idFieldName};
8663
- let __saveData = JSON.stringify(JSON.stringify(formData));
8664
- `;
8665
- const requestAdaptor = `
8666
- ${saveDataTpl}
8667
- api.data.query = query.replace('{__saveData}', __saveData);
8668
- return api;
8669
- `;
8670
8961
 
8671
- return {
8672
- method: 'post',
8673
- url: getApi$2(),
8674
- data: apiData,
8675
- requestAdaptor: requestAdaptor,
8676
- adaptor: `
8677
- if(payload.errors){
8678
- payload.status = 2;
8679
- payload.msg = payload.errors[0].message;
8680
- const revert = api.data.$self.event.data.revert;
8681
- revert && revert();
8962
+ const defaults = options.defaults;
8963
+ if (defaults) {
8964
+ const listSchema = defaults.listSchema || {};
8965
+ body = defaultsDeep({}, listSchema, body);
8966
+ const headerSchema = defaults.headerSchema;
8967
+ const footerSchema = defaults.footerSchema;
8968
+ if (headerSchema || footerSchema) {
8969
+ let wrappedBody = [body];
8970
+ if (headerSchema) {
8971
+ if(___default.isArray(headerSchema)){
8972
+ wrappedBody = ___default.union(headerSchema,wrappedBody);
8973
+ }
8974
+ else {
8975
+ wrappedBody.unshift(headerSchema);
8976
+ }
8682
8977
  }
8683
- return payload;
8684
- `,
8685
- headers: {
8686
- Authorization: "Bearer ${context.tenantId},${context.authToken}"
8978
+ if (footerSchema) {
8979
+ if(___default.isArray(footerSchema)){
8980
+ wrappedBody = ___default.union(wrappedBody,footerSchema);
8981
+ }
8982
+ else {
8983
+ wrappedBody.push(footerSchema);
8984
+ }
8985
+ }
8986
+ body = wrappedBody;
8987
+ }
8988
+ }
8989
+ // console.timeEnd('getObjectCRUD');
8990
+ // TODO: data应该只留loaded,其他属性都改为从上层传递下来
8991
+ return {
8992
+ type: 'service',
8993
+ className: '',
8994
+ id: `service_${id}`,
8995
+ name: `page`,
8996
+ data: {
8997
+ objectName: objectSchema.name,
8998
+ // _id: null,
8999
+ recordPermissions: objectSchema.permissions,
9000
+ uiSchema: objectSchema,
9001
+ // loaded: false //crud接收适配器中设置为true,否则就是刷新浏览器第一次加载
9002
+ },
9003
+ body: body
8687
9004
  }
8688
- };
8689
9005
  }
8690
9006
 
8691
- /**
8692
- * 列表视图Calendar amisSchema
8693
- * @param {*} objectSchema 对象UISchema
8694
- * @returns amisSchema
8695
- */
8696
- async function getObjectCalendar(objectSchema, calendarOptions, options) {
8697
- const permissions = objectSchema.permissions;
8698
- if (!options) {
8699
- options = {};
8700
- }
8701
-
8702
- calendarOptions = Object.assign({}, DEFAULT_CALENDAR_OPTIONS, omitBy(calendarOptions, isNil));
9007
+ const getGlobalData = (mode)=>{
9008
+ const user = getSteedosAuth();
9009
+ return {mode: mode, user: user, spaceId: user.spaceId, userId: user.userId}
9010
+ };
8703
9011
 
8704
- const titleFields = calendarOptions.title || [
8705
- calendarOptions.startDateExpr,
8706
- calendarOptions.endDateExpr,
8707
- calendarOptions.allDayExpr,
8708
- calendarOptions.textExpr
8709
- ];
8710
- let fields = [];
8711
- each(titleFields, function (n) {
8712
- if (objectSchema.fields[n]) {
8713
- fields.push(objectSchema.fields[n]);
9012
+ const getFormFields = (objectSchema, formProps)=>{
9013
+ /**
9014
+ * fieldsExtend: 重写字段定义
9015
+ * fields: 包含的字段
9016
+ * excludedFields: 排除的字段
9017
+ */
9018
+ const { fieldsExtend, fields: includedFields, excludedFields } = formProps;
9019
+
9020
+ let fields = {};
9021
+ // 以uiSchema fields 为基础, 遍历字段, 并更新字段定义
9022
+ ___default.forEach(objectSchema.fields, (field, fieldName)=>{
9023
+ if(!lodash.has(field, "name")){
9024
+ field.name = fieldName;
9025
+ }
9026
+ if(fieldsExtend && fieldsExtend[fieldName]){
9027
+ fields[field.name] = Object.assign({}, field, fieldsExtend[fieldName], {name: field.name});
9028
+ }else {
9029
+ fields[field.name] = field;
8714
9030
  }
8715
9031
  });
8716
9032
 
8717
- if (objectSchema.fields[calendarOptions.allDayExpr]) {
8718
- fields.push(objectSchema.fields[calendarOptions.allDayExpr]);
9033
+ if(!___default.isEmpty(includedFields) && ___default.isArray(includedFields)){
9034
+ const includedFieldsMap = {};
9035
+ ___default.each(includedFields, (fName, index)=>{
9036
+ if(fields[fName]){
9037
+ includedFieldsMap[fName] = Object.assign({}, fields[fName], {sort_no: index});
9038
+ }
9039
+ });
9040
+ fields = includedFieldsMap;
8719
9041
  }
8720
9042
 
8721
- let sort = options.sort;
8722
- if (!sort) {
8723
- const sortField = options.sortField;
8724
- const sortOrder = options.sortOrder;
8725
- if (sortField) {
8726
- let sortStr = sortField + ' ' + sortOrder || 'asc';
8727
- sort = sortStr;
8728
- }
8729
- }
8730
- let initialView = calendarOptions.currentView;
8731
- if (initialView) {
8732
- // day, week, month, agenda
8733
- switch (initialView) {
8734
- case "day":
8735
- initialView = "timeGridDay";
8736
- break;
8737
- case "week":
8738
- initialView = "timeGridWeek";
8739
- break;
8740
- case "month":
8741
- initialView = "dayGridMonth";
8742
- break;
8743
- case "agenda":
8744
- initialView = "listWeek";
8745
- break;
8746
- }
8747
- }
8748
- else {
8749
- initialView = "timeGridWeek";
9043
+ if(!___default.isEmpty(excludedFields) && ___default.isArray(excludedFields)){
9044
+ ___default.each(excludedFields, (fName)=>{
9045
+ delete fields[fName];
9046
+ });
8750
9047
  }
8751
9048
 
8752
- options.calendarOptions = calendarOptions;
8753
- const api = await getCalendarApi(objectSchema, fields, options);
9049
+ return lodash.sortBy(___default.values(fields), "sort_no");
9050
+ };
8754
9051
 
8755
- const onGetEventsScript = `
8756
- const api = ${JSON.stringify(api)};
8757
- event.data.calendarOptions = ${JSON.stringify(calendarOptions)};
8758
- doAction({
8759
- "actionType": 'ajax',
8760
- "args": {
8761
- "api": api
9052
+ async function getObjectForm(objectSchema, ctx){
9053
+ const { recordId, formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, tabId, appId, defaults } = ctx;
9054
+ const fields = ___default.values(objectSchema.fields);
9055
+ const formFields = getFormFields(objectSchema, ctx);
9056
+ const formSchema = defaults && defaults.formSchema || {};
9057
+ if(___default.has(formSchema, 'className')){
9058
+ formSchema.className = 'steedos-amis-form';
9059
+ }
9060
+ const amisSchema = {
9061
+ type: 'service',
9062
+ className: 'p-0',
9063
+ name: `page_edit_${recordId}`,
9064
+ api: await getEditFormInitApi(objectSchema, recordId, fields, ctx),
9065
+ data:{
9066
+ editFormInited: false
8762
9067
  },
8763
- });
8764
- `;
9068
+ // data: {global: getGlobalData('edit'), recordId: recordId, objectName: objectSchema.name, context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
9069
+ initApi: null,
9070
+ initFetch: null ,
9071
+ body: [defaultsDeep({}, formSchema, {
9072
+ type: "form",
9073
+ mode: layout,
9074
+ data: {
9075
+ "&": "${initialValues}"
9076
+ },
9077
+ labelAlign,
9078
+ persistData: false,
9079
+ resetAfterSubmit: true,
9080
+ preventEnterSubmit: true,
9081
+ promptPageLeave: true,
9082
+ canAccessSuperData: false,
9083
+ name: `form_edit_${recordId}`,
9084
+ debug: false,
9085
+ title: "",
9086
+ submitText: "", // amis 表单不显示提交按钮, 表单提交由项目代码接管
9087
+ api: await getSaveApi(objectSchema, recordId, fields, ctx),
9088
+ initFetch: recordId != 'new',
9089
+ body: await getFormBody(fields, formFields, ctx),
9090
+ panelClassName:'m-0 sm:rounded-lg shadow-none border-none',
9091
+ bodyClassName: 'p-0',
9092
+ className: 'steedos-amis-form',
9093
+ hiddenOn: "${editFormInited != true}",
9094
+ onEvent: {
9095
+ "submitSucc": {
9096
+ "weight": 0,
9097
+ "actions": [
9098
+ {
9099
+ "actionType": "broadcast",
9100
+ "args": {
9101
+ "eventName": `@data.changed.${objectSchema.name}`
9102
+ },
9103
+ "data": {
9104
+ "objectName": `${objectSchema.name}`,
9105
+ "displayAs": "${displayAs}"
9106
+ }
9107
+ },
9108
+ {
9109
+ "actionType": "broadcast",
9110
+ "args": {
9111
+ "eventName": "@data.changed.${_master.objectName}"
9112
+ },
9113
+ "data": {
9114
+ "objectName": "${_master.objectName}",
9115
+ "_isRelated": "${_isRelated || _master._isRelated}"
9116
+ },
9117
+ "expression": `\${_master.objectName != '${objectSchema.name}' && _master.objectName}`
9118
+ },
9119
+ // {
9120
+ // "actionType": "custom",
9121
+ // "script": "debugger;"
9122
+ // },
9123
+ // {
9124
+ // "args": {},
9125
+ // "actionType": "closeDialog"
9126
+ // }
9127
+ ]
9128
+ }
9129
+ }
9130
+ })]
9131
+ };
9132
+ if(formSchema.id){
9133
+ amisSchema.id = `service-${formSchema.id}`;
9134
+ }
9135
+ return amisSchema;
9136
+ }
8765
9137
 
8766
- const onSelectScript = `
8767
- const data = event.data;
8768
- const doc = {};
8769
- doc["${calendarOptions.startDateExpr}"] = data.start;
8770
- doc["${calendarOptions.endDateExpr}"] = data.end;
8771
- doc["${calendarOptions.allDayExpr}"] = data.allDay;
8772
- doc["${calendarOptions.textExpr}"] = data.title;
8773
- // ObjectForm会认作用域下的变量值
8774
- // TODO: 待组件支持initValues属性后应该改掉,不应该通过data直接传值
8775
- // TODO: 全天事件属性传入doc了但是没有生效,需要手动在ObjectForm中勾选全天事件
8776
- const title = "新建 ${objectSchema.label}";
8777
- doAction(
8778
- {
8779
- "actionType": "dialog",
8780
- "dialog": {
8781
- "type": "dialog",
8782
- "title": title,
8783
- "body": [
8784
- {
8785
- "type": "steedos-object-form",
8786
- "objectApiName": "\${objectName}",
8787
- "mode": "edit",
8788
- "defaultData": doc,
8789
- "onEvent": {
8790
- "submitSucc": {
8791
- "weight": 0,
9138
+ async function getObjectDetail(objectSchema, recordId, ctx){
9139
+ const { formFactor, layout = formFactor === 'SMALL' ? 'normal' : "normal", labelAlign, formInitProps } = ctx;
9140
+ const fields = ___default.values(objectSchema.fields);
9141
+ const formFields = getFormFields(objectSchema, ctx);
9142
+ const serviceId = `service_detail_page`;
9143
+ return {
9144
+ type: 'service',
9145
+ name: `page_readonly_${recordId}`,
9146
+ id: serviceId,
9147
+ data: {global: getGlobalData('read'), context: {rootUrl: getRootUrl(), tenantId: getTenantId(), authToken: getAuthToken()}},
9148
+ api: await getReadonlyFormInitApi(objectSchema, recordId, fields, formInitProps),
9149
+ body: [
9150
+ {
9151
+ "type": "wrapper", //form 的 hiddenOn 会导致 form onEvent 异常, 使用wrapper包裹一次form,并在wrapper上控制显隐
9152
+ hiddenOn: "${recordLoaded != true}",
9153
+ "className": "p-0 m-0",
9154
+ "body": {
9155
+ type: "form",
9156
+ mode: layout,
9157
+ labelAlign,
9158
+ persistData: false,
9159
+ promptPageLeave: false,
9160
+ name: `form_readonly_${recordId}`,
9161
+ debug: false,
9162
+ title: "",
9163
+ data: {
9164
+ "formData": "$$"
9165
+ },
9166
+ wrapWithPanel: false,
9167
+ body: await getFormBody(map(fields, (field)=>{field.readonly = true; return field;}), map(formFields, (field)=>{field.readonly = true; return field;}), Object.assign({}, ctx, {showSystemFields: true})),
9168
+ className: 'steedos-amis-form bg-white',
9169
+ actions: [], // 不显示表单默认的提交按钮
9170
+ onEvent: {
9171
+ [`@data.changed.${objectSchema.name}`]: { // 由于amis service 组件的 onEvent 存在bug ,此处借助form来刷新 上层 service https://github.com/baidu/amis/issues/6294
8792
9172
  "actions": [
8793
9173
  {
9174
+ "actionType": "reload",
9175
+ "componentId": serviceId,
9176
+ "expression": "this.__deletedRecord != true"
9177
+ },
9178
+ {
9179
+ // "args": {
9180
+ // "url": "/app/${appId}/${objectName}/grid/${side_listview_id}",
9181
+ // "blank": false
9182
+ // },
8794
9183
  "actionType": "custom",
8795
- "script": "event.data.view?.calendar.refetchEvents();"
9184
+ "script": "Steedos.goBack()",
9185
+ "expression": "this.__deletedRecord === true"
8796
9186
  }
8797
9187
  ]
8798
9188
  }
8799
9189
  }
8800
- }
8801
- ],
8802
- "closeOnEsc": false,
8803
- "closeOnOutside": false,
8804
- "showCloseButton": true,
8805
- "size": "lg"
8806
- }
8807
- });
8808
- `;
8809
-
8810
- const onEventClickScript = `
8811
- const data = event.data;
8812
- const eventData = data.event;
8813
- const appId = data.appId;
8814
- const objectName = data.objectName;
8815
- const eventId = data.event && data.event.id;
8816
- doAction({
8817
- "actionType": "dialog",
8818
- "dialog": {
8819
- "type": "dialog",
8820
- "title": "",
8821
- "body": [
8822
- {
8823
- "type": "steedos-record-detail",
8824
- "objectApiName": "\${objectName}",
8825
- "recordId": data.event && data.event.id
8826
- }
8827
- ],
8828
- "closeOnEsc": false,
8829
- "closeOnOutside": false,
8830
- "showCloseButton": true,
8831
- "size": "lg",
8832
- "actions": []
8833
- }
8834
- });
8835
- `;
8836
-
8837
- const recordId = "${event.id}";
8838
- const recordPermissionsApi = getCalendarRecordPermissionsApi(objectSchema, recordId);
8839
- const recordSaveApi = getCalendarRecordSaveApi(objectSchema, calendarOptions);
8840
-
8841
- const businessHours = {
8842
- daysOfWeek: [1, 2, 3, 4, 5],
8843
- startTime: '08:00',
8844
- endTime: '18:00',
8845
- };
8846
- if (!isEmpty(calendarOptions.startDayHour)) {
8847
- businessHours.startTime = `${calendarOptions.startDayHour}:00`;
8848
- }
8849
- if (!isEmpty(calendarOptions.endDayHour)) {
8850
- businessHours.endTime = `${calendarOptions.endDayHour}:00`;
8851
- }
8852
-
8853
- const onEvent = {
8854
- "getEvents": {
8855
- "weight": 0,
8856
- "actions": [
8857
- {
8858
- "componentId": "",
8859
- "args": {
8860
- },
8861
- "actionType": "custom",
8862
- "script": onGetEventsScript
8863
- }
8864
- ]
8865
- },
8866
- "select": {
8867
- "weight": 0,
8868
- "actions": [
8869
- {
8870
- "componentId": "",
8871
- "args": {
8872
- },
8873
- "actionType": "custom",
8874
- "script": onSelectScript
8875
- }
8876
- ]
8877
- },
8878
- "eventClick": {
8879
- "weight": 0,
8880
- "actions": [
8881
- {
8882
- "componentId": "",
8883
- "args": {
8884
- },
8885
- "actionType": "custom",
8886
- "script": onEventClickScript
8887
- }
8888
- ]
8889
- },
8890
- "eventAdd": {
8891
- "weight": 0,
8892
- "actions": [
8893
- {
8894
- "componentId": "",
8895
- "args": {
8896
9190
  },
8897
- "actionType": "custom",
8898
- "script": "console.log('eventAdd'); console.log(event);"
8899
- }
8900
- ]
8901
- },
8902
- "eventChange": {
8903
- "weight": 0,
8904
- "actions": [
8905
- {
8906
- "actionType": 'ajax',
8907
- "args": {
8908
- "api": recordPermissionsApi
8909
- }
8910
- },
8911
- {
8912
- "actionType": "toast",
8913
- "expression": "!event.data.editable",
8914
- "args": {
8915
- "msgType": "error",
8916
- "msg": "您没有编辑该记录的权限!",
8917
- "position": "top-center"
8918
9191
  }
8919
- },
8920
- {
8921
- "actionType": 'ajax',
8922
- "expression": "event.data.editable",
8923
- "args": {
8924
- "api": recordSaveApi,
8925
- "messages": {
8926
- "success": objectSchema.label + "修改成功",
8927
- "failed": objectSchema.label + "修改失败!"
9192
+ ],
9193
+ onEvent: {
9194
+ "fetchInited": {
9195
+ "weight": 0,
9196
+ "actions": [
9197
+ {
9198
+ actionType: 'broadcast',
9199
+ eventName: "recordLoaded",
9200
+ args: {
9201
+ eventName: "recordLoaded"
9202
+ },
9203
+ data: {
9204
+ objectName: "${event.data.__objectName}",
9205
+ record: "${event.data.__record}"
9206
+ },
9207
+ expression: "${event.data.__response.error != true}"
9208
+ },
9209
+ {
9210
+ "actionType": "setValue",
9211
+ "args": {
9212
+ value: {
9213
+ "recordLoaded": true,
9214
+ }
9215
+ },
9216
+ expression: "${event.data.__response.error != true}"
8928
9217
  }
9218
+ ]
8929
9219
  }
8930
9220
  }
8931
- ]
8932
- },
8933
- "eventRemove": {
8934
- "weight": 0,
8935
- "actions": [
8936
- {
8937
- "componentId": "",
8938
- "args": {
8939
- },
8940
- "actionType": "custom",
8941
- "script": "console.log('eventRemove'); console.log(event);"
8942
- }
8943
- ]
8944
- },
8945
- "eventsSet": {
8946
- "weight": 0,
8947
- "actions": [
8948
- {
8949
- "componentId": "",
8950
- "args": {
8951
- },
8952
- "actionType": "custom",
8953
- "script": "console.log('eventsSet'); console.log(event);"
8954
- }
8955
- ]
8956
- }
8957
- };
8958
-
8959
- Object.assign(onEvent, options.onEvent);
8960
-
8961
- const config = options.config || {};
8962
- if(config.eventContent && typeof config.eventContent === "string"){
8963
- const hasReturn = /\breturn\b/.test(config.eventContent);
8964
- if(hasReturn){
8965
- try {
8966
- // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8967
- let fn = new Function("arg", config.eventContent);
8968
- config.eventContent = fn;
8969
- } catch (e) {
8970
- console.warn(e);
8971
- }
8972
- }
8973
- }
8974
-
8975
- if(config.noEventsContent && typeof config.noEventsContent === "string"){
8976
- const hasReturn = /\breturn\b/.test(config.noEventsContent);
8977
- if(hasReturn){
8978
- try {
8979
- // 如果是包括return语句的字符串,则按函数解析,见 https://fullcalendar.io/docs/content-injection
8980
- let fn = new Function("arg", config.noEventsContent);
8981
- config.noEventsContent = fn;
8982
- } catch (e) {
8983
- console.warn(e);
8984
- }
8985
9221
  }
8986
- }
8987
-
8988
- const amisSchema = {
8989
- "type": "steedos-fullcalendar",
8990
- "label": "",
8991
- "name": "fullcalendar",
8992
- "placeholder":"${additionalFilters}",//用于触发reload
8993
- "editable": permissions.allowEdit,
8994
- "selectable": permissions.allowCreate,
8995
- "selectMirror": permissions.allowCreate,
8996
- "initialView": initialView,
8997
- "businessHours": businessHours,
8998
- ...config,
8999
- "onEvent": onEvent
9000
- };
9001
- return amisSchema;
9002
9222
  }
9003
9223
 
9004
9224
  /*
@@ -9420,8 +9640,8 @@ async function getRelatedListSchema(
9420
9640
  /*
9421
9641
  * @Author: baozhoutao@steedos.com
9422
9642
  * @Date: 2022-07-05 15:55:39
9423
- * @LastEditors: baozhoutao@steedos.com
9424
- * @LastEditTime: 2023-04-28 11:11:29
9643
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
9644
+ * @LastEditTime: 2023-06-04 17:36:49
9425
9645
  * @Description:
9426
9646
  */
9427
9647
 
@@ -9752,7 +9972,8 @@ async function getListSchema(
9752
9972
  "requestAdaptor": listView.requestAdaptor,
9753
9973
  "adaptor": listView.adaptor,
9754
9974
  "headerToolbarItems": ctx.headerToolbarItems,
9755
- "filterVisible": ctx.filterVisible
9975
+ "filterVisible": ctx.filterVisible,
9976
+ "rowClassNameExpr": ctx.rowClassNameExpr
9756
9977
  };
9757
9978
  return {
9758
9979
  uiSchema,