midway-fatcms 0.0.1-beta.60 → 0.0.1-beta.63

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.
Files changed (27) hide show
  1. package/dist/config/config.default.js +2 -2
  2. package/dist/controller/gateway/FileController.d.ts +2 -0
  3. package/dist/controller/gateway/FileController.js +15 -0
  4. package/dist/controller/gateway/PublicApiController.d.ts +4 -0
  5. package/dist/controller/gateway/PublicApiController.js +19 -2
  6. package/dist/libs/crud-pro/interfaces.d.ts +2 -0
  7. package/dist/libs/crud-pro/models/keys.d.ts +4 -0
  8. package/dist/libs/crud-pro/models/keys.js +5 -0
  9. package/dist/libs/crud-pro/services/CrudProExecuteFuncService.js +13 -0
  10. package/dist/libs/crud-pro/services/CrudProGenSqlCondition.js +15 -0
  11. package/dist/libs/crud-pro/utils/ModelUtils.js +6 -1
  12. package/dist/service/crudstd/CrudStdRelationService.js +20 -11
  13. package/dist/service/curd/CurdMixByAccountService.js +28 -7
  14. package/dist/service/curd/CurdMixUtils.d.ts +7 -1
  15. package/dist/service/curd/CurdMixUtils.js +59 -5
  16. package/package.json +1 -1
  17. package/src/config/config.default.ts +2 -2
  18. package/src/controller/gateway/FileController.ts +15 -1
  19. package/src/controller/gateway/PublicApiController.ts +17 -0
  20. package/src/libs/crud-pro/interfaces.ts +3 -0
  21. package/src/libs/crud-pro/models/keys.ts +6 -0
  22. package/src/libs/crud-pro/services/CrudProExecuteFuncService.ts +17 -0
  23. package/src/libs/crud-pro/services/CrudProGenSqlCondition.ts +22 -2
  24. package/src/libs/crud-pro/utils/ModelUtils.ts +6 -1
  25. package/src/service/crudstd/CrudStdRelationService.ts +25 -12
  26. package/src/service/curd/CurdMixByAccountService.ts +31 -8
  27. package/src/service/curd/CurdMixUtils.ts +74 -5
@@ -35,7 +35,7 @@ exports.default = (appInfo) => {
35
35
  jsonLimit: '10mb',
36
36
  textLimit: '10mb',
37
37
  xmlLimit: '10mb',
38
- ignore: ['/ns/gw/proxy/*', '/ns/gw/file/uploadFile', '/ns/api/manage/deploy/uploadAssets'], // 忽略代理路径的 body 解析
38
+ ignore: ['/ns/gw/proxy/*', '/ns/gw/file/uploadFile', '/ns/gw/file/uploadFilePublic', '/ns/api/manage/deploy/uploadAssets'], // 忽略代理路径的 body 解析
39
39
  },
40
40
  mysql2: {
41
41
  fatcms: {
@@ -119,7 +119,7 @@ exports.default = (appInfo) => {
119
119
  // base64: boolean,设置原始body是否是base64格式,默认为false,一般用于腾讯云的兼容
120
120
  base64: false,
121
121
  // 仅在匹配路径到 /api/upload 的时候去解析 body 中的文件信息
122
- match: ['/ns/gw/file/uploadFile', '/ns/api/manage/deploy/uploadAssets'],
122
+ match: ['/ns/gw/file/uploadFile', '/ns/gw/file/uploadFilePublic', '/ns/api/manage/deploy/uploadAssets'],
123
123
  },
124
124
  view: {
125
125
  rootDir: {
@@ -8,6 +8,7 @@ import { CommonResult } from '../../libs/utils/common-dto';
8
8
  export declare class FileController extends BaseApiController {
9
9
  protected ctx: Context;
10
10
  protected fileCenterService: FileCenterService;
11
+ uploadFilePublic(files: any, fields: any, queryData: any): Promise<CommonResult>;
11
12
  /**
12
13
  * 上传普通文件。必须是登录用户才能上传。
13
14
  * @param files
@@ -15,6 +16,7 @@ export declare class FileController extends BaseApiController {
15
16
  * @param queryData
16
17
  */
17
18
  uploadFile(files: any, fields: any, queryData: any): Promise<CommonResult>;
19
+ private uploadFilePrivate;
18
20
  /**
19
21
  * 文件下载或预览
20
22
  * @param byMethod
@@ -29,6 +29,9 @@ function isTrue(obj) {
29
29
  * 文件上传下载服务
30
30
  */
31
31
  let FileController = class FileController extends BaseApiController_1.BaseApiController {
32
+ async uploadFilePublic(files, fields, queryData) {
33
+ return this.uploadFilePrivate(files, fields, queryData);
34
+ }
32
35
  /**
33
36
  * 上传普通文件。必须是登录用户才能上传。
34
37
  * @param files
@@ -36,6 +39,9 @@ let FileController = class FileController extends BaseApiController_1.BaseApiCon
36
39
  * @param queryData
37
40
  */
38
41
  async uploadFile(files, fields, queryData) {
42
+ return this.uploadFilePrivate(files, fields, queryData);
43
+ }
44
+ async uploadFilePrivate(files, fields, queryData) {
39
45
  const accessType = (queryData === null || queryData === void 0 ? void 0 : queryData.accessType) || (fields === null || fields === void 0 ? void 0 : fields.accessType) || bizmodels_1.AccessType.open;
40
46
  const referer = this.ctx.req.headers.referer;
41
47
  if (!Object.keys(bizmodels_1.AccessType).includes(accessType)) {
@@ -106,6 +112,15 @@ __decorate([
106
112
  (0, core_1.Inject)(),
107
113
  __metadata("design:type", FileCenterService_1.FileCenterService)
108
114
  ], FileController.prototype, "fileCenterService", void 0);
115
+ __decorate([
116
+ (0, core_1.Post)('/uploadFilePublic', { middleware: [(0, permission_middleware_1.checkLogin)()] }),
117
+ __param(0, (0, core_1.Files)()),
118
+ __param(1, (0, core_1.Fields)()),
119
+ __param(2, (0, core_1.Query)()),
120
+ __metadata("design:type", Function),
121
+ __metadata("design:paramtypes", [Object, Object, Object]),
122
+ __metadata("design:returntype", Promise)
123
+ ], FileController.prototype, "uploadFilePublic", null);
109
124
  __decorate([
110
125
  (0, core_1.Post)('/uploadFile', { middleware: [(0, permission_middleware_1.checkPermission)([SystemPerm_1.SystemFuncCode.DocMangeWrite, SystemPerm_1.SystemFuncCode.FileMangeWrite, SystemPerm_1.SystemFuncCode.UserAccountMangeWrite])] }),
111
126
  __param(0, (0, core_1.Files)()),
@@ -24,4 +24,8 @@ export declare class PublicApiController extends BaseApiController {
24
24
  * 获取配置的枚举项信息: 都是无需鉴权的
25
25
  */
26
26
  getEnumInfo(): Promise<CommonResult>;
27
+ /**
28
+ * 获取应用配置信息
29
+ */
30
+ getSysAppInfoByAppCode(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
27
31
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.PublicApiController = void 0;
13
13
  const core_1 = require("@midwayjs/core");
14
14
  const _ = require("lodash");
15
+ const keys_1 = require("../../libs/crud-pro/models/keys");
15
16
  const BaseApiController_1 = require("../base/BaseApiController");
16
17
  const SystemTables_1 = require("../../models/SystemTables");
17
18
  const EnumInfoService_1 = require("../../service/EnumInfoService");
@@ -19,7 +20,7 @@ const common_dto_1 = require("../../libs/utils/common-dto");
19
20
  const functions_1 = require("../../libs/utils/functions");
20
21
  const WorkbenchService_1 = require("../../service/WorkbenchService");
21
22
  const SystemPerm_1 = require("../../models/SystemPerm");
22
- const keys_1 = require("../../libs/crud-pro/models/keys");
23
+ const keys_2 = require("../../libs/crud-pro/models/keys");
23
24
  /**
24
25
  * 公开的API,无需鉴权,所有人可以直接访问
25
26
  */
@@ -71,7 +72,7 @@ let PublicApiController = class PublicApiController extends BaseApiController_1.
71
72
  // 特殊的devops菜单
72
73
  map['devops'] = {
73
74
  menu_list: [],
74
- hasPermission: this.ctx.userSession.isAuthPass(keys_1.KeysOfAuthType.byRoleCode, [SystemPerm_1.SystemRoleCode.DevOpsWriter, SystemPerm_1.SystemRoleCode.DevOpsViewer, SystemPerm_1.SystemRoleCode.SuperAdmin]),
75
+ hasPermission: this.ctx.userSession.isAuthPass(keys_2.KeysOfAuthType.byRoleCode, [SystemPerm_1.SystemRoleCode.DevOpsWriter, SystemPerm_1.SystemRoleCode.DevOpsViewer, SystemPerm_1.SystemRoleCode.SuperAdmin]),
75
76
  };
76
77
  return common_dto_1.CommonResult.successRes(map);
77
78
  }
@@ -119,6 +120,16 @@ let PublicApiController = class PublicApiController extends BaseApiController_1.
119
120
  const enumInfos = await this.enumInfoService.queryEnumInfo(codeList, refreshCache);
120
121
  return common_dto_1.CommonResult.successRes(enumInfos);
121
122
  }
123
+ /**
124
+ * 获取应用配置信息
125
+ */
126
+ async getSysAppInfoByAppCode() {
127
+ return this.executeSysSimpleSQL('sys_app', keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE, {
128
+ validateCfg: {
129
+ 'condition.app_code': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
130
+ },
131
+ });
132
+ }
122
133
  };
123
134
  __decorate([
124
135
  (0, core_1.Inject)(),
@@ -156,6 +167,12 @@ __decorate([
156
167
  __metadata("design:paramtypes", []),
157
168
  __metadata("design:returntype", Promise)
158
169
  ], PublicApiController.prototype, "getEnumInfo", null);
170
+ __decorate([
171
+ (0, core_1.Post)('/getSysAppInfoByAppCode'),
172
+ __metadata("design:type", Function),
173
+ __metadata("design:paramtypes", []),
174
+ __metadata("design:returntype", Promise)
175
+ ], PublicApiController.prototype, "getSysAppInfoByAppCode", null);
159
176
  PublicApiController = __decorate([
160
177
  (0, core_1.Controller)('/ns/gw/api/publicApi')
161
178
  ], PublicApiController);
@@ -105,6 +105,8 @@ export interface IFuncCfgModel extends Record<any, any> {
105
105
  contextAsString?: string;
106
106
  contextAsNumber?: string;
107
107
  contextAsBool?: string;
108
+ executeExpressReturnObject?: string;
109
+ executeExpressReturnString?: string;
108
110
  message?: string;
109
111
  }
110
112
  export interface ISqlCfgModel extends IBaseCfgModel {
@@ -101,6 +101,10 @@ export declare const KeysOfConditions: {
101
101
  $NOT_LIKE_INCLUDE: string;
102
102
  $MATCH: string;
103
103
  $MATCH_BOOL: string;
104
+ /**
105
+ * SELECT * FROM tms_biz.表 WHERE JSON_CONTAINS(`related_user1`, JSON_ARRAY('2512274'), '$');
106
+ */
107
+ $JSON_ARRAY_CONTAINS: string;
104
108
  COMPARE_KEYS: Set<string>;
105
109
  ALL_KEYS: Set<string>;
106
110
  };
@@ -115,6 +115,10 @@ exports.KeysOfConditions = {
115
115
  $NOT_LIKE_INCLUDE: '$notLikeInclude',
116
116
  $MATCH: '$match',
117
117
  $MATCH_BOOL: '$matchBool',
118
+ /**
119
+ * SELECT * FROM tms_biz.表 WHERE JSON_CONTAINS(`related_user1`, JSON_ARRAY('2512274'), '$');
120
+ */
121
+ $JSON_ARRAY_CONTAINS: '$jsonArrayContains',
118
122
  COMPARE_KEYS: new Set([]),
119
123
  ALL_KEYS: new Set([]),
120
124
  };
@@ -137,6 +141,7 @@ function initKeysOfConditions() {
137
141
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$LIKE_INCLUDE);
138
142
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$NOT_LIKE);
139
143
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$NOT_LIKE_INCLUDE);
144
+ addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$JSON_ARRAY_CONTAINS);
140
145
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$MATCH);
141
146
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$MATCH_BOOL);
142
147
  addIgnoreCase(exports.KeysOfConditions.COMPARE_KEYS, exports.KeysOfConditions.$RANGE);
@@ -5,6 +5,8 @@ const CrudProServiceBase_1 = require("./CrudProServiceBase");
5
5
  const TypeUtils_1 = require("../utils/TypeUtils");
6
6
  const MixinUtils_1 = require("../utils/MixinUtils");
7
7
  const _ = require("lodash");
8
+ const moment = require("moment");
9
+ const ejs = require("ejs");
8
10
  const exceptions_1 = require("../exceptions");
9
11
  const keys_1 = require("../models/keys");
10
12
  const { isNil, isNumeric } = TypeUtils_1.TypeUtils;
@@ -20,6 +22,17 @@ class CrudProExecuteFuncService extends CrudProServiceBase_1.CrudProServiceBase
20
22
  if (funCfg.___PLAIN_OBJECT___ === true) {
21
23
  return funCfg;
22
24
  }
25
+ const funcContextAny = funcContext;
26
+ funcContextAny.moment = moment;
27
+ funcContextAny._ = _;
28
+ if (isNotNil(funCfg.executeExpressReturnString)) {
29
+ const expressResult = ejs.render(funCfg.executeExpressReturnString, funcContextAny);
30
+ return expressResult;
31
+ }
32
+ if (isNotNil(funCfg.executeExpressReturnObject)) {
33
+ const expressResult = ejs.render(funCfg.executeExpressReturnObject, funcContextAny);
34
+ return JSON.parse(expressResult);
35
+ }
23
36
  if (isNotNil(funCfg.const)) {
24
37
  return funCfg.const;
25
38
  }
@@ -208,6 +208,16 @@ class CrudProGenSqlCondition {
208
208
  tmpSql = `${toSqlColumnName(key)} like concat('%', ?::text, '%')`; // like包含
209
209
  }
210
210
  }
211
+ else if (equalsIgnoreCase(keys_1.KeysOfConditions.$JSON_ARRAY_CONTAINS, compare)) {
212
+ if (this.sqlCfg.sqlDbType === keys_1.SqlDbType.mysql) {
213
+ tmpArgList.push(value0);
214
+ tmpSql = `JSON_CONTAINS( ${toSqlColumnName(key)} , JSON_ARRAY(?), '$')`; // MYSQL JSON_CONTAINS包含
215
+ }
216
+ if (this.sqlCfg.sqlDbType === keys_1.SqlDbType.postgres) {
217
+ tmpArgList.push(value0);
218
+ tmpSql = `${toSqlColumnName(key)} @> ('["' || ? || '"]')::jsonb`; // POSTGRES JSON_CONTAINS包含
219
+ }
220
+ }
211
221
  else if (equalsIgnoreCase(keys_1.KeysOfConditions.$NOT_LIKE_INCLUDE, compare)) {
212
222
  tmpArgList.push(value0);
213
223
  tmpSql = `${toSqlColumnName(key)} COLLATE UTF8MB4_GENERAL_CI not like concat('%',?, '%')`; // like不包含
@@ -308,6 +318,11 @@ class CrudProGenSqlCondition {
308
318
  throwCommonException(keys_1.KeysOfConditions.$NOT_LIKE_INCLUDE, '字符串');
309
319
  }
310
320
  }
321
+ else if (equalsIgnoreCase(keys_1.KeysOfConditions.$JSON_ARRAY_CONTAINS, compare)) {
322
+ if (!isBasicType(value0)) {
323
+ throwCommonException(keys_1.KeysOfConditions.$JSON_ARRAY_CONTAINS, '字符串或数字');
324
+ }
325
+ }
311
326
  else if (equalsIgnoreCase(keys_1.KeysOfConditions.$MATCH, compare)) {
312
327
  if (!isBasicType(value0)) {
313
328
  throwCommonException(keys_1.KeysOfConditions.$MATCH, '字符串');
@@ -36,7 +36,12 @@ const ModelUtils = {
36
36
  return defaultConfigs_1.DEFAULT_MAX_LIMIT;
37
37
  },
38
38
  checkFuncCfgValid(cfgModel) {
39
- const arr = [cfgModel.functionName, cfgModel.const, cfgModel.constString, cfgModel.constNumber, cfgModel.constBool, cfgModel.context, cfgModel.contextAsString, cfgModel.contextAsNumber, cfgModel.contextAsBool];
39
+ const arr = [
40
+ cfgModel.functionName, cfgModel.const, cfgModel.constString, cfgModel.constNumber,
41
+ cfgModel.constBool, cfgModel.context,
42
+ cfgModel.contextAsString, cfgModel.contextAsNumber, cfgModel.contextAsBool,
43
+ cfgModel.executeExpressReturnObject, cfgModel.executeExpressReturnString
44
+ ];
40
45
  for (let i = 0; i < arr.length; i++) {
41
46
  const arrElement = arr[i];
42
47
  if (typeof arrElement !== 'undefined') {
@@ -65,6 +65,16 @@ class ColumnsRelationMaker {
65
65
  }
66
66
  }
67
67
  }
68
+ function addMarkerColumnRelation(maker, dataIndex, componentName) {
69
+ // 关联用户信息
70
+ if (componentName === CrudStdConstant_1.tableColumnRenders.RenderUserInfo) {
71
+ maker.addColumnRelationByAccount(dataIndex);
72
+ }
73
+ // 关联枚举文案/状态标签颜色
74
+ if (componentName === CrudStdConstant_1.tableColumnRenders.RenderDictEnumText || componentName === CrudStdConstant_1.tableColumnRenders.RenderDictEnumStatus) {
75
+ maker.addColumnRelationByDictEnumStatus(dataIndex);
76
+ }
77
+ }
68
78
  let CrudStdRelationService = class CrudStdRelationService extends BaseService_1.BaseService {
69
79
  async addCfgModelColumnsRelation(cfgModel, appInfo) {
70
80
  var _a;
@@ -77,22 +87,21 @@ let CrudStdRelationService = class CrudStdRelationService extends BaseService_1.
77
87
  const tableColumn = tableColumns[i];
78
88
  const dataIndex = _.get(tableColumn, 'dataIndex');
79
89
  const componentName = _.get(tableColumn, 'component.componentName');
80
- // 关联用户信息
81
- if (componentName === CrudStdConstant_1.tableColumnRenders.RenderUserInfo) {
82
- maker.addColumnRelationByAccount(dataIndex);
83
- }
84
- // 关联枚举文案/状态标签颜色
85
- if (componentName === CrudStdConstant_1.tableColumnRenders.RenderDictEnumText || componentName === CrudStdConstant_1.tableColumnRenders.RenderDictEnumStatus) {
86
- maker.addColumnRelationByDictEnumStatus(dataIndex);
87
- }
90
+ addMarkerColumnRelation(maker, dataIndex, componentName);
88
91
  // 子属性的配置
89
92
  const balloonTipFields = _.get(tableColumn, 'component.props.balloonTipFields');
90
93
  if (Array.isArray(balloonTipFields) && balloonTipFields.length > 0) {
91
94
  for (let j = 0; j < balloonTipFields.length; j++) {
92
95
  const { component, name } = balloonTipFields[j] || {};
93
- if (component === CrudStdConstant_1.tableColumnRenders.RenderUserInfo) {
94
- maker.addColumnRelationByAccount(name);
95
- }
96
+ addMarkerColumnRelation(maker, name, component);
97
+ }
98
+ }
99
+ // 子属性的配置
100
+ const linkDataConfig = _.get(tableColumn, 'component.props.linkDataConfig');
101
+ if (Array.isArray(linkDataConfig) && linkDataConfig.length > 0) {
102
+ for (let j = 0; j < linkDataConfig.length; j++) {
103
+ const { component, name } = linkDataConfig[j] || {};
104
+ addMarkerColumnRelation(maker, name, component);
96
105
  }
97
106
  }
98
107
  }
@@ -20,21 +20,29 @@ const MixinUtils_1 = require("../../libs/crud-pro/utils/MixinUtils");
20
20
  const global_config_1 = require("../../libs/global-config/global-config");
21
21
  const dictMixUtils = new CurdMixUtils_1.CrudMixUtils(CurdMixUtils_1.RelatedType.accountBasic);
22
22
  const TMP_CTX_KEY = _.uniqueId('CurdMixByAccountService');
23
+ const TMP_CTX_KEY2 = _.uniqueId('CurdMixByAccountService2');
23
24
  let CurdMixByAccountService = class CurdMixByAccountService {
24
25
  async handleExecuteContextPrepare(executeContext) {
25
- const { SystemDbName, SystemDbType, toFatcmsUserAccountId } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
26
+ const { SystemDbName, SystemDbType } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
26
27
  const relations = dictMixUtils.pickColumnRelations(executeContext);
27
28
  if (!relations || relations.length === 0) {
28
29
  return;
29
30
  }
31
+ const isArrayModeMap = new Map();
30
32
  const accountIds = new Set();
31
33
  dictMixUtils.forEachRowAndColumnsRelation(executeContext, (row, columnRelation) => {
32
34
  const { sourceColumn } = columnRelation;
33
35
  if (sourceColumn) {
34
36
  const accountId = _.get(row, sourceColumn);
35
37
  if (accountId) {
36
- const fatcmsUserAccountId = toFatcmsUserAccountId(accountId);
37
- accountIds.add(fatcmsUserAccountId);
38
+ const { isArray, fatcmsUserAccountIdList, fatcmsUserAccountId } = (0, CurdMixUtils_1.toFatcmsUserAccountIdList)(accountId);
39
+ if (isArray) {
40
+ isArrayModeMap.set(sourceColumn, true);
41
+ fatcmsUserAccountIdList.forEach(item => accountIds.add(item));
42
+ }
43
+ else if (fatcmsUserAccountId) {
44
+ accountIds.add(fatcmsUserAccountId);
45
+ }
38
46
  }
39
47
  }
40
48
  });
@@ -59,9 +67,11 @@ let CurdMixByAccountService = class CurdMixByAccountService {
59
67
  const res = await this.curdProService.executeCrudByCfg(reqJson, cfgModel);
60
68
  const userInfos = res.getResRows();
61
69
  executeContext[TMP_CTX_KEY] = MixinUtils_1.MixinUtils.toNewMap(userInfos, (obj) => obj.account_id);
70
+ executeContext[TMP_CTX_KEY2] = isArrayModeMap;
62
71
  }
63
72
  async handleExecuteContext(executeContext) {
64
73
  const userInfoMap = executeContext[TMP_CTX_KEY];
74
+ const isArrayModeMap = executeContext[TMP_CTX_KEY2];
65
75
  if (!userInfoMap || userInfoMap.size === 0) {
66
76
  return;
67
77
  }
@@ -69,10 +79,21 @@ let CurdMixByAccountService = class CurdMixByAccountService {
69
79
  const sourceColumn = columnRelation.sourceColumn;
70
80
  const targetColumns = columnRelation.targetColumns;
71
81
  if (!Array.isArray(targetColumns) || targetColumns.length === 0) {
72
- columnRelation.targetColumns = [
73
- { from: 'nick_name', to: `${sourceColumn}_user.nick_name` },
74
- { from: 'avatar', to: `${sourceColumn}_user.avatar` },
75
- ];
82
+ const isArrayMode = isArrayModeMap.get(sourceColumn) || false;
83
+ if (isArrayMode === true) {
84
+ columnRelation.targetColumns = [
85
+ { from: 'nick_name', to: `${sourceColumn}_array_info[$ARRAY_INDEX].nick_name` },
86
+ { from: 'avatar', to: `${sourceColumn}_array_info[$ARRAY_INDEX].avatar` },
87
+ { from: 'account_id', to: `${sourceColumn}_array_info[$ARRAY_INDEX].account_id` },
88
+ ];
89
+ }
90
+ else {
91
+ columnRelation.targetColumns = [
92
+ { from: 'nick_name', to: `${sourceColumn}_user.nick_name` },
93
+ { from: 'avatar', to: `${sourceColumn}_user.avatar` },
94
+ { from: 'account_id', to: `${sourceColumn}_user.account_id` },
95
+ ];
96
+ }
76
97
  }
77
98
  dictMixUtils.copyUserInfoToRowNoRelatedCode(row, userInfoMap, columnRelation);
78
99
  });
@@ -9,6 +9,12 @@ declare enum RelatedType {
9
9
  workbenchBasic = "workbenchBasic"
10
10
  }
11
11
  declare type FuncRowColumnRelation = (row: any, columnRelation: ColumnRelation) => void;
12
+ interface IFatcmsUserAccountIdList {
13
+ isArray: boolean;
14
+ fatcmsUserAccountId?: string;
15
+ fatcmsUserAccountIdList?: string[];
16
+ }
17
+ declare function toFatcmsUserAccountIdList(accountId: any): IFatcmsUserAccountIdList;
12
18
  declare class CrudMixUtils {
13
19
  private readonly relatedType;
14
20
  constructor(relatedType: RelatedType);
@@ -48,4 +54,4 @@ declare class CrudMixUtils {
48
54
  */
49
55
  copyUserInfoToRowNoRelatedCode(row: any, map: Map<string, any>, columnRelation: ColumnRelation): void;
50
56
  }
51
- export { CrudMixUtils, RelatedType, FuncRowColumnRelation };
57
+ export { CrudMixUtils, RelatedType, FuncRowColumnRelation, toFatcmsUserAccountIdList };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RelatedType = exports.CrudMixUtils = void 0;
3
+ exports.toFatcmsUserAccountIdList = exports.RelatedType = exports.CrudMixUtils = void 0;
4
4
  const keys_1 = require("../../libs/crud-pro/models/keys");
5
5
  const MixinUtils_1 = require("../../libs/crud-pro/utils/MixinUtils");
6
6
  const global_config_1 = require("../../libs/global-config/global-config");
@@ -94,6 +94,59 @@ function copyByArraySourceValue(row, sourceValue, targetColumns, getValue) {
94
94
  }
95
95
  return resultObj.isSetArray;
96
96
  }
97
+ function toFatcmsUserAccountIdList(accountId) {
98
+ const { toFatcmsUserAccountId } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
99
+ if (!accountId) {
100
+ return {
101
+ isArray: false,
102
+ fatcmsUserAccountId: null
103
+ };
104
+ }
105
+ // 数字形式
106
+ if (typeof accountId === 'number') {
107
+ return {
108
+ isArray: false,
109
+ fatcmsUserAccountId: toFatcmsUserAccountId("" + accountId),
110
+ };
111
+ }
112
+ if (typeof accountId === 'string') {
113
+ const json = (0, functions_1.parseJsonObject)(accountId);
114
+ // 数组形式
115
+ if (json && Array.isArray(json) && json.length > 0) {
116
+ return {
117
+ isArray: true,
118
+ fatcmsUserAccountIdList: json.map(item => {
119
+ if (typeof item === 'string' || typeof item === 'number') {
120
+ return toFatcmsUserAccountId("" + item);
121
+ }
122
+ return null;
123
+ }).filter(item => item !== null),
124
+ };
125
+ }
126
+ // 单值形式
127
+ return {
128
+ isArray: false,
129
+ fatcmsUserAccountId: toFatcmsUserAccountId(accountId),
130
+ };
131
+ }
132
+ // 数组形式
133
+ if (Array.isArray(accountId)) {
134
+ return {
135
+ isArray: true,
136
+ fatcmsUserAccountIdList: accountId.map(item => {
137
+ if (typeof item === 'string' || typeof item === 'number') {
138
+ return toFatcmsUserAccountId("" + item);
139
+ }
140
+ return null;
141
+ }).filter(item => item !== null),
142
+ };
143
+ }
144
+ return {
145
+ isArray: false,
146
+ fatcmsUserAccountId: null
147
+ };
148
+ }
149
+ exports.toFatcmsUserAccountIdList = toFatcmsUserAccountIdList;
97
150
  class CrudMixUtils {
98
151
  constructor(relatedType) {
99
152
  this.relatedType = relatedType;
@@ -257,8 +310,7 @@ class CrudMixUtils {
257
310
  if (!accountId) {
258
311
  return;
259
312
  }
260
- const { toFatcmsUserAccountId } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
261
- const fatcmsUserAccountId = toFatcmsUserAccountId(accountId);
313
+ const { isArray, fatcmsUserAccountIdList, fatcmsUserAccountId } = toFatcmsUserAccountIdList(accountId);
262
314
  const getValue = (code) => {
263
315
  if (!map) {
264
316
  return null;
@@ -268,8 +320,10 @@ class CrudMixUtils {
268
320
  }
269
321
  return map[code];
270
322
  };
271
- const isSetArray = copyByArraySourceValue(row, fatcmsUserAccountId, targetColumns, getValue);
272
- if (!isSetArray) {
323
+ if (isArray) {
324
+ copyByArraySourceValue(row, fatcmsUserAccountIdList, targetColumns, getValue);
325
+ }
326
+ else if (fatcmsUserAccountId) {
273
327
  copyBySingleSourceValue(row, fatcmsUserAccountId, targetColumns, getValue);
274
328
  }
275
329
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "midway-fatcms",
3
- "version": "0.0.1-beta.60",
3
+ "version": "0.0.1-beta.63",
4
4
  "description": "This is a midway component sample",
5
5
  "main": "dist/index.js",
6
6
  "typings": "index.d.ts",
@@ -41,7 +41,7 @@ export default (appInfo: any) => {
41
41
  jsonLimit: '10mb',
42
42
  textLimit: '10mb',
43
43
  xmlLimit: '10mb',
44
- ignore: ['/ns/gw/proxy/*', '/ns/gw/file/uploadFile', '/ns/api/manage/deploy/uploadAssets'], // 忽略代理路径的 body 解析
44
+ ignore: ['/ns/gw/proxy/*', '/ns/gw/file/uploadFile', '/ns/gw/file/uploadFilePublic', '/ns/api/manage/deploy/uploadAssets'], // 忽略代理路径的 body 解析
45
45
  },
46
46
 
47
47
  mysql2: {
@@ -130,7 +130,7 @@ export default (appInfo: any) => {
130
130
  // base64: boolean,设置原始body是否是base64格式,默认为false,一般用于腾讯云的兼容
131
131
  base64: false,
132
132
  // 仅在匹配路径到 /api/upload 的时候去解析 body 中的文件信息
133
- match: ['/ns/gw/file/uploadFile', '/ns/api/manage/deploy/uploadAssets'],
133
+ match: ['/ns/gw/file/uploadFile', '/ns/gw/file/uploadFilePublic', '/ns/api/manage/deploy/uploadAssets'],
134
134
  },
135
135
 
136
136
  view: {
@@ -5,7 +5,7 @@ import { BaseApiController } from '../base/BaseApiController';
5
5
  import { BizException } from '@/models/devops';
6
6
  import { AccessType, FILE_GET_TYPES } from '@/models/bizmodels';
7
7
  import { FileCenterService, PATH_PREFIX, toDownloadPaths, isImageFile } from '@/service/FileCenterService';
8
- import { checkPermission } from '@/middleware/permission.middleware';
8
+ import { checkLogin, checkPermission } from '@/middleware/permission.middleware';
9
9
  import { CommonResult } from '@/libs/utils/common-dto';
10
10
  import { SystemFuncCode } from '@/models/SystemPerm';
11
11
 
@@ -24,6 +24,13 @@ export class FileController extends BaseApiController {
24
24
  @Inject()
25
25
  protected fileCenterService: FileCenterService;
26
26
 
27
+ @Post('/uploadFilePublic', { middleware: [checkLogin()] })
28
+ async uploadFilePublic(@Files() files, @Fields() fields, @Query() queryData): Promise<CommonResult> {
29
+ return this.uploadFilePrivate(files, fields, queryData);
30
+ }
31
+
32
+
33
+
27
34
  /**
28
35
  * 上传普通文件。必须是登录用户才能上传。
29
36
  * @param files
@@ -32,6 +39,13 @@ export class FileController extends BaseApiController {
32
39
  */
33
40
  @Post('/uploadFile', { middleware: [checkPermission([SystemFuncCode.DocMangeWrite, SystemFuncCode.FileMangeWrite, SystemFuncCode.UserAccountMangeWrite])] })
34
41
  async uploadFile(@Files() files, @Fields() fields, @Query() queryData): Promise<CommonResult> {
42
+ return this.uploadFilePrivate(files, fields, queryData);
43
+ }
44
+
45
+
46
+
47
+
48
+ private async uploadFilePrivate(files: any, fields: any, queryData: any) {
35
49
  const accessType = queryData?.accessType || fields?.accessType || AccessType.open;
36
50
  const referer = this.ctx.req.headers.referer;
37
51
 
@@ -1,6 +1,7 @@
1
1
  import { Controller, Get, Inject, Post } from '@midwayjs/core';
2
2
  import { Context } from '@midwayjs/koa';
3
3
  import * as _ from 'lodash';
4
+ import { KeysOfSimpleSQL, KeysOfValidators } from '@/libs/crud-pro/models/keys';
4
5
  import { BaseApiController } from '../base/BaseApiController';
5
6
  import { SystemTables } from '@/models/SystemTables';
6
7
  import { EnumInfoService } from '@/service/EnumInfoService';
@@ -137,4 +138,20 @@ export class PublicApiController extends BaseApiController {
137
138
  const enumInfos = await this.enumInfoService.queryEnumInfo(codeList, refreshCache);
138
139
  return CommonResult.successRes(enumInfos);
139
140
  }
141
+
142
+
143
+
144
+ /**
145
+ * 获取应用配置信息
146
+ */
147
+ @Post('/getSysAppInfoByAppCode')
148
+ async getSysAppInfoByAppCode() {
149
+ return this.executeSysSimpleSQL('sys_app', KeysOfSimpleSQL.SIMPLE_QUERY_ONE, {
150
+ validateCfg: {
151
+ 'condition.app_code': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
152
+ },
153
+ });
154
+ }
155
+
156
+
140
157
  }
@@ -125,6 +125,9 @@ export interface IFuncCfgModel extends Record<any, any> {
125
125
  contextAsNumber?: string; // 从context中取值
126
126
  contextAsBool?: string; // 从context中取值
127
127
 
128
+ executeExpressReturnObject?: string; // 执行表达式,返回对象。可以包含context中的变量。
129
+ executeExpressReturnString?: string; // 执行表达式,返回字符串。可以包含context中的变量。
130
+
128
131
  message?: string; // 在校验阶段有用,其他阶段没有用
129
132
  }
130
133
 
@@ -121,6 +121,11 @@ export const KeysOfConditions = {
121
121
  $MATCH: '$match', // 全文索引 {age:1, name:{"$match":"张"} }
122
122
  $MATCH_BOOL: '$matchBool', // 全文索引 {age:1, name:{"$matchBool":"张"} }
123
123
 
124
+ /**
125
+ * SELECT * FROM tms_biz.表 WHERE JSON_CONTAINS(`related_user1`, JSON_ARRAY('2512274'), '$');
126
+ */
127
+ $JSON_ARRAY_CONTAINS: '$jsonArrayContains', // 全文索引 { related_user1:{"$jsonArrayContains":"2512274"} }
128
+
124
129
  COMPARE_KEYS: new Set<string>([]),
125
130
  ALL_KEYS: new Set<string>([]),
126
131
  };
@@ -145,6 +150,7 @@ function initKeysOfConditions() {
145
150
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$LIKE_INCLUDE);
146
151
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$NOT_LIKE);
147
152
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$NOT_LIKE_INCLUDE);
153
+ addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$JSON_ARRAY_CONTAINS);
148
154
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$MATCH);
149
155
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$MATCH_BOOL);
150
156
  addIgnoreCase(KeysOfConditions.COMPARE_KEYS, KeysOfConditions.$RANGE);
@@ -4,6 +4,8 @@ import { FuncContext } from '../models/FuncContext';
4
4
  import { TypeUtils } from '../utils/TypeUtils';
5
5
  import { MixinUtils } from '../utils/MixinUtils';
6
6
  import * as _ from 'lodash';
7
+ import * as moment from 'moment';
8
+ import * as ejs from 'ejs';
7
9
  import { CommonException, Exceptions } from '../exceptions';
8
10
  import { KeysOfFunCtx } from '../models/keys';
9
11
 
@@ -24,6 +26,21 @@ class CrudProExecuteFuncService extends CrudProServiceBase {
24
26
  return funCfg;
25
27
  }
26
28
 
29
+ const funcContextAny: any = funcContext;
30
+ funcContextAny.moment = moment;
31
+ funcContextAny._ = _;
32
+
33
+ if (isNotNil(funCfg.executeExpressReturnString)) {
34
+ const expressResult = ejs.render(funCfg.executeExpressReturnString, funcContextAny);
35
+ return expressResult;
36
+ }
37
+
38
+ if (isNotNil(funCfg.executeExpressReturnObject)) {
39
+ const expressResult = ejs.render(funCfg.executeExpressReturnObject, funcContextAny);
40
+ return JSON.parse(expressResult);
41
+ }
42
+
43
+
27
44
  if (isNotNil(funCfg.const)) {
28
45
  return funCfg.const;
29
46
  }
@@ -227,7 +227,22 @@ class CrudProGenSqlCondition {
227
227
  if (this.sqlCfg.sqlDbType === SqlDbType.postgres) {
228
228
  tmpSql = `${toSqlColumnName(key)} like concat('%', ?::text, '%')`; // like包含
229
229
  }
230
- } else if (equalsIgnoreCase(KeysOfConditions.$NOT_LIKE_INCLUDE, compare)) {
230
+ }
231
+
232
+ else if (equalsIgnoreCase(KeysOfConditions.$JSON_ARRAY_CONTAINS, compare)) {
233
+ if (this.sqlCfg.sqlDbType === SqlDbType.mysql) {
234
+ tmpArgList.push(value0);
235
+ tmpSql = `JSON_CONTAINS( ${toSqlColumnName(key)} , JSON_ARRAY(?), '$')`; // MYSQL JSON_CONTAINS包含
236
+ }
237
+
238
+ if (this.sqlCfg.sqlDbType === SqlDbType.postgres) {
239
+ tmpArgList.push(value0);
240
+ tmpSql = `${toSqlColumnName(key)} @> ('["' || ? || '"]')::jsonb`; // POSTGRES JSON_CONTAINS包含
241
+ }
242
+
243
+ }
244
+
245
+ else if (equalsIgnoreCase(KeysOfConditions.$NOT_LIKE_INCLUDE, compare)) {
231
246
  tmpArgList.push(value0);
232
247
  tmpSql = `${toSqlColumnName(key)} COLLATE UTF8MB4_GENERAL_CI not like concat('%',?, '%')`; // like不包含
233
248
 
@@ -323,7 +338,12 @@ class CrudProGenSqlCondition {
323
338
  if (!isBasicType(value0)) {
324
339
  throwCommonException(KeysOfConditions.$NOT_LIKE_INCLUDE, '字符串');
325
340
  }
326
- } else if (equalsIgnoreCase(KeysOfConditions.$MATCH, compare)) {
341
+ } else if (equalsIgnoreCase(KeysOfConditions.$JSON_ARRAY_CONTAINS, compare)) {
342
+ if (!isBasicType(value0)) {
343
+ throwCommonException(KeysOfConditions.$JSON_ARRAY_CONTAINS, '字符串或数字');
344
+ }
345
+ }
346
+ else if (equalsIgnoreCase(KeysOfConditions.$MATCH, compare)) {
327
347
  if (!isBasicType(value0)) {
328
348
  throwCommonException(KeysOfConditions.$MATCH, '字符串');
329
349
  }
@@ -41,7 +41,12 @@ const ModelUtils = {
41
41
  return DEFAULT_MAX_LIMIT;
42
42
  },
43
43
  checkFuncCfgValid(cfgModel: IFuncCfgModel): boolean {
44
- const arr = [cfgModel.functionName, cfgModel.const, cfgModel.constString, cfgModel.constNumber, cfgModel.constBool, cfgModel.context, cfgModel.contextAsString, cfgModel.contextAsNumber, cfgModel.contextAsBool];
44
+ const arr = [
45
+ cfgModel.functionName, cfgModel.const, cfgModel.constString, cfgModel.constNumber,
46
+ cfgModel.constBool, cfgModel.context,
47
+ cfgModel.contextAsString, cfgModel.contextAsNumber, cfgModel.contextAsBool,
48
+ cfgModel.executeExpressReturnObject, cfgModel.executeExpressReturnString
49
+ ];
45
50
  for (let i = 0; i < arr.length; i++) {
46
51
  const arrElement = arr[i];
47
52
  if (typeof arrElement !== 'undefined') {
@@ -68,6 +68,19 @@ class ColumnsRelationMaker {
68
68
  }
69
69
 
70
70
 
71
+ function addMarkerColumnRelation(maker: ColumnsRelationMaker, dataIndex: string, componentName: string) {
72
+ // 关联用户信息
73
+ if (componentName === tableColumnRenders.RenderUserInfo) {
74
+ maker.addColumnRelationByAccount(dataIndex);
75
+ }
76
+
77
+ // 关联枚举文案/状态标签颜色
78
+ if (componentName === tableColumnRenders.RenderDictEnumText || componentName === tableColumnRenders.RenderDictEnumStatus) {
79
+ maker.addColumnRelationByDictEnumStatus(dataIndex);
80
+ }
81
+ }
82
+
83
+
71
84
  @Provide()
72
85
  export class CrudStdRelationService extends BaseService {
73
86
  @Inject()
@@ -90,24 +103,24 @@ export class CrudStdRelationService extends BaseService {
90
103
  const dataIndex = _.get(tableColumn, 'dataIndex');
91
104
  const componentName = _.get(tableColumn, 'component.componentName');
92
105
 
93
- // 关联用户信息
94
- if (componentName === tableColumnRenders.RenderUserInfo) {
95
- maker.addColumnRelationByAccount(dataIndex);
96
- }
97
-
98
- // 关联枚举文案/状态标签颜色
99
- if (componentName === tableColumnRenders.RenderDictEnumText || componentName === tableColumnRenders.RenderDictEnumStatus) {
100
- maker.addColumnRelationByDictEnumStatus(dataIndex);
101
- }
106
+ addMarkerColumnRelation(maker, dataIndex, componentName);
102
107
 
103
108
  // 子属性的配置
104
109
  const balloonTipFields = _.get(tableColumn, 'component.props.balloonTipFields');
105
110
  if (Array.isArray(balloonTipFields) && balloonTipFields.length > 0) {
106
111
  for (let j = 0; j < balloonTipFields.length; j++) {
107
112
  const { component, name } = balloonTipFields[j] || {};
108
- if (component === tableColumnRenders.RenderUserInfo) {
109
- maker.addColumnRelationByAccount(name);
110
- }
113
+ addMarkerColumnRelation(maker, name, component);
114
+ }
115
+ }
116
+
117
+
118
+ // 子属性的配置
119
+ const linkDataConfig = _.get(tableColumn, 'component.props.linkDataConfig');
120
+ if (Array.isArray(linkDataConfig) && linkDataConfig.length > 0) {
121
+ for (let j = 0; j < linkDataConfig.length; j++) {
122
+ const { component, name } = linkDataConfig[j] || {};
123
+ addMarkerColumnRelation(maker, name, component);
111
124
  }
112
125
  }
113
126
 
@@ -3,7 +3,7 @@ import { Context } from '@midwayjs/koa';
3
3
  import * as _ from 'lodash';
4
4
  import { CurdProService } from './CurdProService';
5
5
  import { HandleExecuteContextType, IExecuteContextHandler } from '@/libs/crud-pro/models/ExecuteContext';
6
- import { CrudMixUtils, RelatedType } from './CurdMixUtils';
6
+ import { CrudMixUtils, RelatedType, toFatcmsUserAccountIdList } from './CurdMixUtils';
7
7
  import { SystemTables } from '@/models/SystemTables';
8
8
  import { KeysOfSimpleSQL } from '@/libs/crud-pro/models/keys';
9
9
  import { ColumnRelation, IRequestCfgModel, IRequestModel } from '@/libs/crud-pro/interfaces';
@@ -13,6 +13,9 @@ import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
13
13
  const dictMixUtils = new CrudMixUtils(RelatedType.accountBasic);
14
14
 
15
15
  const TMP_CTX_KEY = _.uniqueId('CurdMixByAccountService');
16
+ const TMP_CTX_KEY2 = _.uniqueId('CurdMixByAccountService2');
17
+
18
+
16
19
 
17
20
  @Provide()
18
21
  export class CurdMixByAccountService implements IExecuteContextHandler {
@@ -23,21 +26,28 @@ export class CurdMixByAccountService implements IExecuteContextHandler {
23
26
  protected curdProService: CurdProService;
24
27
 
25
28
  async handleExecuteContextPrepare(executeContext: HandleExecuteContextType) {
26
- const { SystemDbName, SystemDbType, toFatcmsUserAccountId } = GLOBAL_STATIC_CONFIG.getConfig();
29
+ const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
27
30
 
28
31
  const relations = dictMixUtils.pickColumnRelations(executeContext);
29
32
  if (!relations || relations.length === 0) {
30
33
  return;
31
34
  }
32
35
 
36
+ const isArrayModeMap = new Map<string, boolean>();
37
+
33
38
  const accountIds = new Set<string>();
34
39
  dictMixUtils.forEachRowAndColumnsRelation(executeContext, (row: any, columnRelation: ColumnRelation) => {
35
40
  const { sourceColumn } = columnRelation;
36
41
  if (sourceColumn) {
37
42
  const accountId = _.get(row, sourceColumn);
38
43
  if (accountId) {
39
- const fatcmsUserAccountId = toFatcmsUserAccountId(accountId);
40
- accountIds.add(fatcmsUserAccountId);
44
+ const { isArray, fatcmsUserAccountIdList, fatcmsUserAccountId } = toFatcmsUserAccountIdList(accountId);
45
+ if(isArray) {
46
+ isArrayModeMap.set(sourceColumn, true);
47
+ fatcmsUserAccountIdList.forEach(item => accountIds.add(item));
48
+ } else if(fatcmsUserAccountId) {
49
+ accountIds.add(fatcmsUserAccountId);
50
+ }
41
51
  }
42
52
  }
43
53
  });
@@ -66,10 +76,13 @@ export class CurdMixByAccountService implements IExecuteContextHandler {
66
76
  const res = await this.curdProService.executeCrudByCfg(reqJson, cfgModel);
67
77
  const userInfos = res.getResRows();
68
78
  executeContext[TMP_CTX_KEY] = MixinUtils.toNewMap(userInfos, (obj: any) => obj.account_id);
79
+ executeContext[TMP_CTX_KEY2] = isArrayModeMap;
69
80
  }
70
81
 
71
82
  async handleExecuteContext(executeContext: HandleExecuteContextType): Promise<void> {
72
83
  const userInfoMap = executeContext[TMP_CTX_KEY] as Map<string, any>;
84
+ const isArrayModeMap = executeContext[TMP_CTX_KEY2] as Map<string, boolean>;
85
+
73
86
  if (!userInfoMap || userInfoMap.size === 0) {
74
87
  return;
75
88
  }
@@ -78,10 +91,20 @@ export class CurdMixByAccountService implements IExecuteContextHandler {
78
91
  const sourceColumn = columnRelation.sourceColumn;
79
92
  const targetColumns = columnRelation.targetColumns;
80
93
  if (!Array.isArray(targetColumns) || targetColumns.length === 0) {
81
- columnRelation.targetColumns = [
82
- { from: 'nick_name', to: `${sourceColumn}_user.nick_name` },
83
- { from: 'avatar', to: `${sourceColumn}_user.avatar` },
84
- ];
94
+ const isArrayMode = isArrayModeMap.get(sourceColumn) || false;
95
+ if(isArrayMode === true) {
96
+ columnRelation.targetColumns = [
97
+ { from: 'nick_name', to: `${sourceColumn}_array_info[$ARRAY_INDEX].nick_name` },
98
+ { from: 'avatar', to: `${sourceColumn}_array_info[$ARRAY_INDEX].avatar` },
99
+ { from: 'account_id', to: `${sourceColumn}_array_info[$ARRAY_INDEX].account_id` },
100
+ ];
101
+ } else {
102
+ columnRelation.targetColumns = [
103
+ { from: 'nick_name', to: `${sourceColumn}_user.nick_name` },
104
+ { from: 'avatar', to: `${sourceColumn}_user.avatar` },
105
+ { from: 'account_id', to: `${sourceColumn}_user.account_id` },
106
+ ];
107
+ }
85
108
  }
86
109
  dictMixUtils.copyUserInfoToRowNoRelatedCode(row, userInfoMap, columnRelation);
87
110
  });
@@ -104,6 +104,74 @@ function copyByArraySourceValue(row: any, sourceValue: any, targetColumns: CopyA
104
104
  return resultObj.isSetArray;
105
105
  }
106
106
 
107
+
108
+
109
+ interface IFatcmsUserAccountIdList {
110
+ isArray: boolean;
111
+ fatcmsUserAccountId?: string;
112
+ fatcmsUserAccountIdList?: string[];
113
+ }
114
+
115
+ function toFatcmsUserAccountIdList(accountId: any): IFatcmsUserAccountIdList {
116
+ const { toFatcmsUserAccountId } = GLOBAL_STATIC_CONFIG.getConfig();
117
+
118
+ if (!accountId) {
119
+ return {
120
+ isArray: false,
121
+ fatcmsUserAccountId: null
122
+ };
123
+ }
124
+
125
+ // 数字形式
126
+ if (typeof accountId === 'number') {
127
+ return {
128
+ isArray: false,
129
+ fatcmsUserAccountId: toFatcmsUserAccountId("" + accountId),
130
+ }
131
+ }
132
+
133
+ if (typeof accountId === 'string') {
134
+ const json = parseJsonObject(accountId);
135
+
136
+ // 数组形式
137
+ if (json && Array.isArray(json) && json.length > 0) {
138
+ return {
139
+ isArray: true,
140
+ fatcmsUserAccountIdList: json.map(item => {
141
+ if (typeof item === 'string' || typeof item === 'number') {
142
+ return toFatcmsUserAccountId("" + item)
143
+ }
144
+ return null;
145
+ }).filter(item => item !== null),
146
+ }
147
+ }
148
+ // 单值形式
149
+ return {
150
+ isArray: false,
151
+ fatcmsUserAccountId: toFatcmsUserAccountId(accountId),
152
+ }
153
+ }
154
+
155
+ // 数组形式
156
+ if (Array.isArray(accountId)) {
157
+ return {
158
+ isArray: true,
159
+ fatcmsUserAccountIdList: accountId.map(item => {
160
+ if (typeof item === 'string' || typeof item === 'number') {
161
+ return toFatcmsUserAccountId("" + item)
162
+ }
163
+ return null;
164
+ }).filter(item => item !== null),
165
+ }
166
+ }
167
+
168
+ return {
169
+ isArray: false,
170
+ fatcmsUserAccountId: null
171
+ };
172
+ }
173
+
174
+
107
175
  class CrudMixUtils {
108
176
  private readonly relatedType: RelatedType;
109
177
  constructor(relatedType: RelatedType) {
@@ -291,8 +359,7 @@ class CrudMixUtils {
291
359
  return;
292
360
  }
293
361
 
294
- const { toFatcmsUserAccountId } = GLOBAL_STATIC_CONFIG.getConfig();
295
- const fatcmsUserAccountId = toFatcmsUserAccountId(accountId);
362
+ const { isArray, fatcmsUserAccountIdList, fatcmsUserAccountId } = toFatcmsUserAccountIdList(accountId);
296
363
 
297
364
  const getValue = (code: string) => {
298
365
  if (!map) {
@@ -304,11 +371,13 @@ class CrudMixUtils {
304
371
  return map[code];
305
372
  };
306
373
 
307
- const isSetArray = copyByArraySourceValue(row, fatcmsUserAccountId, targetColumns, getValue);
308
- if (!isSetArray) {
374
+ if (isArray) {
375
+ copyByArraySourceValue(row, fatcmsUserAccountIdList, targetColumns, getValue);
376
+ } else if (fatcmsUserAccountId) {
309
377
  copyBySingleSourceValue(row, fatcmsUserAccountId, targetColumns, getValue);
310
378
  }
379
+
311
380
  }
312
381
  }
313
382
 
314
- export { CrudMixUtils, RelatedType, FuncRowColumnRelation };
383
+ export { CrudMixUtils, RelatedType, FuncRowColumnRelation, toFatcmsUserAccountIdList };