@steedos-widgets/amis-lib 1.2.13 → 1.2.15

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