@steedos-widgets/amis-lib 1.2.14 → 1.2.15

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