midway-fatcms 0.0.1-beta.61 → 0.0.1-beta.64
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/config/config.default.js +2 -2
- package/dist/controller/gateway/FileController.d.ts +2 -0
- package/dist/controller/gateway/FileController.js +15 -0
- package/dist/libs/crud-pro/interfaces.d.ts +2 -0
- package/dist/libs/crud-pro/models/keys.d.ts +4 -0
- package/dist/libs/crud-pro/models/keys.js +5 -0
- package/dist/libs/crud-pro/services/CrudProExecuteFuncService.js +13 -0
- package/dist/libs/crud-pro/services/CrudProGenSqlCondition.js +15 -0
- package/dist/libs/crud-pro/utils/ModelUtils.js +6 -1
- package/dist/libs/utils/parseConfig.d.ts +1 -0
- package/dist/libs/utils/parseConfig.js +3 -0
- package/dist/models/bizmodels.d.ts +7 -2
- package/dist/service/AuthService.d.ts +1 -1
- package/dist/service/AuthService.js +5 -1
- package/dist/service/EnumInfoService.js +1 -1
- package/dist/service/crudstd/CrudStdRelationService.js +20 -11
- package/dist/service/crudstd/CrudStdService.d.ts +1 -0
- package/dist/service/crudstd/CrudStdService.js +13 -2
- package/dist/service/curd/CurdMixByAccountService.js +28 -7
- package/dist/service/curd/CurdMixUtils.d.ts +7 -1
- package/dist/service/curd/CurdMixUtils.js +59 -5
- package/package.json +1 -1
- package/src/config/config.default.ts +2 -2
- package/src/controller/gateway/FileController.ts +15 -1
- package/src/libs/crud-pro/interfaces.ts +3 -0
- package/src/libs/crud-pro/models/keys.ts +6 -0
- package/src/libs/crud-pro/services/CrudProExecuteFuncService.ts +17 -0
- package/src/libs/crud-pro/services/CrudProGenSqlCondition.ts +22 -2
- package/src/libs/crud-pro/utils/ModelUtils.ts +6 -1
- package/src/libs/utils/parseConfig.ts +4 -0
- package/src/models/bizmodels.ts +8 -2
- package/src/service/AuthService.ts +6 -1
- package/src/service/EnumInfoService.ts +1 -1
- package/src/service/crudstd/CrudStdRelationService.ts +25 -12
- package/src/service/crudstd/CrudStdService.ts +15 -2
- package/src/service/curd/CurdMixByAccountService.ts +31 -8
- 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)()),
|
|
@@ -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 = [
|
|
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') {
|
|
@@ -14,6 +14,9 @@ function parseTreeTableToIEnumInfo(dataSource) {
|
|
|
14
14
|
label: label || nodeName,
|
|
15
15
|
value: value || key,
|
|
16
16
|
};
|
|
17
|
+
if (item && typeof item.style === 'string' && item.style) {
|
|
18
|
+
enumInfo.style = item.style.trim();
|
|
19
|
+
}
|
|
17
20
|
if (children) {
|
|
18
21
|
enumInfo.children = children;
|
|
19
22
|
}
|
|
@@ -17,6 +17,7 @@ export interface ITableBaseInfo {
|
|
|
17
17
|
export interface IStdCrudCfgObj {
|
|
18
18
|
tableBaseInfo: ITableBaseInfo;
|
|
19
19
|
authSetting: any;
|
|
20
|
+
kanbanAuthSetting: any;
|
|
20
21
|
actionColumns?: any[];
|
|
21
22
|
queryFormFields?: any[];
|
|
22
23
|
tableColumns?: any[];
|
|
@@ -29,9 +30,13 @@ export interface ICrudStdAppInfo {
|
|
|
29
30
|
actionsMap?: any;
|
|
30
31
|
status: number;
|
|
31
32
|
}
|
|
33
|
+
export interface ISettingKeyActionCfg {
|
|
34
|
+
settingKey: string;
|
|
35
|
+
hasOperationPerm: boolean;
|
|
36
|
+
}
|
|
32
37
|
export interface ICrudStdAppInfoForSettingKey extends ICrudStdAppInfo {
|
|
33
|
-
settingKeyActionCfg?:
|
|
34
|
-
buttonSettingKeyActionCfg?:
|
|
38
|
+
settingKeyActionCfg?: ISettingKeyActionCfg;
|
|
39
|
+
buttonSettingKeyActionCfg?: ISettingKeyActionCfg;
|
|
35
40
|
authConfig?: string[];
|
|
36
41
|
authType?: string;
|
|
37
42
|
}
|
|
@@ -39,7 +39,7 @@ export declare class AuthService {
|
|
|
39
39
|
* @param loginName
|
|
40
40
|
* @param workbenchCode
|
|
41
41
|
*/
|
|
42
|
-
createUserSession(loginName: string, workbenchCode: string): Promise<{
|
|
42
|
+
createUserSession(loginName: string, workbenchCode: string, bizExt?: any): Promise<{
|
|
43
43
|
sessionId: string;
|
|
44
44
|
loginName: string;
|
|
45
45
|
accountId: any;
|
|
@@ -107,7 +107,7 @@ let AuthService = class AuthService {
|
|
|
107
107
|
* @param loginName
|
|
108
108
|
* @param workbenchCode
|
|
109
109
|
*/
|
|
110
|
-
async createUserSession(loginName, workbenchCode) {
|
|
110
|
+
async createUserSession(loginName, workbenchCode, bizExt) {
|
|
111
111
|
const userAccount = await this.queryUserAccountByLoginName(loginName);
|
|
112
112
|
if (!userAccount) {
|
|
113
113
|
throw new exceptions_1.CommonException('USER_ACCOUNT_NOT_EXIST', '用户账号不存在');
|
|
@@ -126,7 +126,11 @@ let AuthService = class AuthService {
|
|
|
126
126
|
accountId,
|
|
127
127
|
workbenchCode,
|
|
128
128
|
accountType: userSession_1.SYS_ACCOUNT_TYPE,
|
|
129
|
+
bizExt: {},
|
|
129
130
|
};
|
|
131
|
+
if (bizExt && typeof bizExt === 'object') {
|
|
132
|
+
sessionInfo.bizExt = bizExt;
|
|
133
|
+
}
|
|
130
134
|
await this.userSessionService.saveUserSession(sessionInfo);
|
|
131
135
|
return {
|
|
132
136
|
sessionId,
|
|
@@ -86,7 +86,7 @@ let EnumInfoService = class EnumInfoService {
|
|
|
86
86
|
return null;
|
|
87
87
|
}
|
|
88
88
|
const rows = (0, parseConfig_1.parseConfigContentToEnumInfo)(obj);
|
|
89
|
-
return rows.map(e => ({ label: e.label, value: e.value, children: e.children })).filter(filterEmpty);
|
|
89
|
+
return rows.map(e => ({ label: e.label, value: e.value, style: e.style, children: e.children })).filter(filterEmpty);
|
|
90
90
|
}
|
|
91
91
|
async queryEnumInfoItemByDict(code) {
|
|
92
92
|
const { SystemDbName, SystemDbType } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
|
|
@@ -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
|
-
|
|
94
|
-
|
|
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
|
}
|
|
@@ -28,6 +28,7 @@ const MixinUtils_1 = require("../../libs/crud-pro/utils/MixinUtils");
|
|
|
28
28
|
exports.SPECIAL_SETTING_KEY = {
|
|
29
29
|
QUERY_LIST: 'QUERY_LIST',
|
|
30
30
|
QUERY_ONE: 'QUERY_ONE',
|
|
31
|
+
KANBAN_VIEW_STATUS_UPDATE: 'KANBAN_VIEW_STATUS_UPDATE', // 看板视图中更新状态
|
|
31
32
|
};
|
|
32
33
|
function isNotEmptyStr(str) {
|
|
33
34
|
return typeof str === 'string' && str.trim().length > 0;
|
|
@@ -59,6 +60,7 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
59
60
|
* 执行普通CRUD
|
|
60
61
|
*/
|
|
61
62
|
async executeStdQuery(stdAction, params, sqlSimpleName) {
|
|
63
|
+
var _a;
|
|
62
64
|
const appCode = stdAction.appCode;
|
|
63
65
|
const appInfo = await this.getParsedCrudStdAppForSettingKey(stdAction);
|
|
64
66
|
const stdCrudCfgObj = appInfo.stdCrudCfgObj;
|
|
@@ -79,7 +81,7 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
79
81
|
if (typeof maxLimit === 'number' && maxLimit > 0) {
|
|
80
82
|
cfgModel.maxLimit = maxLimit;
|
|
81
83
|
}
|
|
82
|
-
if (!appInfo.settingKeyActionCfg.hasOperationPerm) {
|
|
84
|
+
if (!((_a = appInfo.settingKeyActionCfg) === null || _a === void 0 ? void 0 : _a.hasOperationPerm)) {
|
|
83
85
|
throw new devops_1.BizException('没有权限');
|
|
84
86
|
}
|
|
85
87
|
// 软删除操作。
|
|
@@ -163,7 +165,16 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
163
165
|
}
|
|
164
166
|
const actionsMap = appInfo.actionsMap;
|
|
165
167
|
const appSchema = appInfo.stdCrudCfgObj;
|
|
166
|
-
|
|
168
|
+
// 看板视图中更新状态
|
|
169
|
+
if (settingKey === exports.SPECIAL_SETTING_KEY.KANBAN_VIEW_STATUS_UPDATE) {
|
|
170
|
+
const kanbanAuthSettingValues = _.get(appSchema, 'kanbanAuthSetting.values');
|
|
171
|
+
const { update_auth_type, update_auth_config_by_func_code, update_auth_config_by_role_code } = (kanbanAuthSettingValues || {});
|
|
172
|
+
const authConfig = update_auth_type === 'byFuncCode' ? update_auth_config_by_func_code : update_auth_config_by_role_code;
|
|
173
|
+
const hasOperationPerm = this.ctx.userSession.isAuthPass(update_auth_type, authConfig);
|
|
174
|
+
appInfo.settingKeyActionCfg = { settingKey, hasOperationPerm };
|
|
175
|
+
}
|
|
176
|
+
// 列表查询或详情查询
|
|
177
|
+
else if (settingKey === exports.SPECIAL_SETTING_KEY.QUERY_LIST || settingKey === exports.SPECIAL_SETTING_KEY.QUERY_ONE) {
|
|
167
178
|
const authSettingValues = _.get(appSchema, 'authSetting.values');
|
|
168
179
|
const { auth_type, auth_config_by_func_code, auth_config_by_role_code } = authSettingValues || {};
|
|
169
180
|
const authConfig = auth_type === 'byFuncCode' ? auth_config_by_func_code : auth_config_by_role_code;
|
|
@@ -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
|
|
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 =
|
|
37
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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 {
|
|
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
|
-
|
|
272
|
-
|
|
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
|
@@ -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
|
|
|
@@ -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
|
-
}
|
|
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.$
|
|
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 = [
|
|
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') {
|
|
@@ -4,6 +4,7 @@ import { parseJsonObject } from './functions';
|
|
|
4
4
|
interface IEnumInfo {
|
|
5
5
|
label: string;
|
|
6
6
|
value: string | number;
|
|
7
|
+
style?: string;
|
|
7
8
|
children?: IEnumInfo[];
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -18,6 +19,9 @@ function parseTreeTableToIEnumInfo(dataSource: any[]): IEnumInfo[] {
|
|
|
18
19
|
label: label || nodeName,
|
|
19
20
|
value: value || key,
|
|
20
21
|
};
|
|
22
|
+
if (item && typeof item.style === 'string' && item.style) {
|
|
23
|
+
enumInfo.style = item.style.trim();
|
|
24
|
+
}
|
|
21
25
|
if (children) {
|
|
22
26
|
enumInfo.children = children;
|
|
23
27
|
}
|
package/src/models/bizmodels.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface ITableBaseInfo {
|
|
|
20
20
|
export interface IStdCrudCfgObj {
|
|
21
21
|
tableBaseInfo: ITableBaseInfo;
|
|
22
22
|
authSetting: any;
|
|
23
|
+
kanbanAuthSetting: any;
|
|
23
24
|
actionColumns?: any[];
|
|
24
25
|
queryFormFields?: any[];
|
|
25
26
|
tableColumns?: any[];
|
|
@@ -34,9 +35,14 @@ export interface ICrudStdAppInfo {
|
|
|
34
35
|
status: number;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
export interface ISettingKeyActionCfg {
|
|
39
|
+
settingKey: string;
|
|
40
|
+
hasOperationPerm: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
export interface ICrudStdAppInfoForSettingKey extends ICrudStdAppInfo {
|
|
38
|
-
settingKeyActionCfg?:
|
|
39
|
-
buttonSettingKeyActionCfg?:
|
|
44
|
+
settingKeyActionCfg?: ISettingKeyActionCfg;
|
|
45
|
+
buttonSettingKeyActionCfg?: ISettingKeyActionCfg;
|
|
40
46
|
authConfig?: string[];
|
|
41
47
|
authType?: string;
|
|
42
48
|
}
|
|
@@ -130,7 +130,7 @@ export class AuthService {
|
|
|
130
130
|
* @param loginName
|
|
131
131
|
* @param workbenchCode
|
|
132
132
|
*/
|
|
133
|
-
public async createUserSession(loginName: string, workbenchCode: string) {
|
|
133
|
+
public async createUserSession(loginName: string, workbenchCode: string, bizExt?: any) {
|
|
134
134
|
const userAccount = await this.queryUserAccountByLoginName(loginName);
|
|
135
135
|
|
|
136
136
|
if (!userAccount) {
|
|
@@ -152,8 +152,13 @@ export class AuthService {
|
|
|
152
152
|
accountId,
|
|
153
153
|
workbenchCode,
|
|
154
154
|
accountType: SYS_ACCOUNT_TYPE,
|
|
155
|
+
bizExt: {},
|
|
155
156
|
};
|
|
156
157
|
|
|
158
|
+
if (bizExt && typeof bizExt === 'object') {
|
|
159
|
+
sessionInfo.bizExt = bizExt;
|
|
160
|
+
}
|
|
161
|
+
|
|
157
162
|
await this.userSessionService.saveUserSession(sessionInfo);
|
|
158
163
|
|
|
159
164
|
return {
|
|
@@ -104,7 +104,7 @@ export class EnumInfoService {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
const rows = parseConfigContentToEnumInfo(obj);
|
|
107
|
-
return rows.map(e => ({ label: e.label, value: e.value, children: e.children })).filter(filterEmpty);
|
|
107
|
+
return rows.map(e => ({ label: e.label, value: e.value, style: e.style, children: e.children })).filter(filterEmpty);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
private async queryEnumInfoItemByDict(code: string): Promise<IEnumInfo[]> {
|
|
@@ -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
|
-
|
|
109
|
-
|
|
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
|
|
|
@@ -22,6 +22,7 @@ import { MixinUtils } from '@/libs/crud-pro/utils/MixinUtils';
|
|
|
22
22
|
export const SPECIAL_SETTING_KEY = {
|
|
23
23
|
QUERY_LIST: 'QUERY_LIST',
|
|
24
24
|
QUERY_ONE: 'QUERY_ONE',
|
|
25
|
+
KANBAN_VIEW_STATUS_UPDATE: 'KANBAN_VIEW_STATUS_UPDATE', // 看板视图中更新状态
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export interface ICrudStdActionParams {
|
|
@@ -115,7 +116,7 @@ export class CrudStdService extends ApiBaseService {
|
|
|
115
116
|
cfgModel.maxLimit = maxLimit;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
if (!appInfo.settingKeyActionCfg
|
|
119
|
+
if (!appInfo.settingKeyActionCfg?.hasOperationPerm) {
|
|
119
120
|
throw new BizException('没有权限');
|
|
120
121
|
}
|
|
121
122
|
|
|
@@ -225,7 +226,19 @@ export class CrudStdService extends ApiBaseService {
|
|
|
225
226
|
const actionsMap = appInfo.actionsMap;
|
|
226
227
|
const appSchema = appInfo.stdCrudCfgObj;
|
|
227
228
|
|
|
228
|
-
|
|
229
|
+
|
|
230
|
+
// 看板视图中更新状态
|
|
231
|
+
if (settingKey === SPECIAL_SETTING_KEY.KANBAN_VIEW_STATUS_UPDATE) {
|
|
232
|
+
|
|
233
|
+
const kanbanAuthSettingValues = _.get(appSchema, 'kanbanAuthSetting.values');
|
|
234
|
+
const { update_auth_type, update_auth_config_by_func_code, update_auth_config_by_role_code } = (kanbanAuthSettingValues || {});
|
|
235
|
+
const authConfig = update_auth_type === 'byFuncCode' ? update_auth_config_by_func_code : update_auth_config_by_role_code;
|
|
236
|
+
const hasOperationPerm = this.ctx.userSession.isAuthPass(update_auth_type as any, authConfig);
|
|
237
|
+
appInfo.settingKeyActionCfg = { settingKey, hasOperationPerm };
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
// 列表查询或详情查询
|
|
241
|
+
else if (settingKey === SPECIAL_SETTING_KEY.QUERY_LIST || settingKey === SPECIAL_SETTING_KEY.QUERY_ONE) {
|
|
229
242
|
const authSettingValues = _.get(appSchema, 'authSetting.values');
|
|
230
243
|
const { auth_type, auth_config_by_func_code, auth_config_by_role_code } = authSettingValues || {};
|
|
231
244
|
const authConfig = auth_type === 'byFuncCode' ? auth_config_by_func_code : auth_config_by_role_code;
|
|
@@ -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
|
|
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 =
|
|
40
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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 {
|
|
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
|
-
|
|
308
|
-
|
|
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 };
|