midway-fatcms 0.0.10 → 0.0.12
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/configuration.d.ts +0 -2
- package/dist/configuration.js +14 -12
- package/dist/controller/gateway/AsyncTaskController.d.ts +1 -0
- package/dist/controller/gateway/AsyncTaskController.js +40 -2
- package/dist/controller/gateway/CrudMtdGatewayController.js +2 -1
- package/dist/controller/gateway/StaticController.d.ts +0 -2
- package/dist/controller/gateway/StaticController.js +4 -39
- package/dist/controller/manage/AccountRoleManageApi.d.ts +2 -1
- package/dist/controller/manage/AccountRoleManageApi.js +34 -0
- package/dist/controller/manage/UserAccountManageApi.js +4 -3
- package/dist/libs/crud-pro/models/keys.d.ts +1 -0
- package/dist/libs/crud-pro/models/keys.js +1 -0
- package/dist/libs/crud-pro/services/CrudProExecuteFuncService.js +2 -2
- package/dist/libs/crud-pro/services/CrudProFieldUpdateService.js +3 -0
- package/dist/libs/crud-pro/services/CrudProTableMetaService.js +2 -2
- package/dist/libs/crud-pro/utils/DatabaseName.js +11 -0
- package/dist/libs/crud-pro/utils/DateTimeUtils.js +1 -1
- package/dist/libs/utils/functions.d.ts +8 -1
- package/dist/libs/utils/functions.js +26 -1
- package/dist/service/AuthService.js +1 -1
- package/dist/service/crudstd/CrudStdService.d.ts +2 -3
- package/dist/service/crudstd/CrudStdService.js +6 -2
- package/dist/service/curd/fixCfgModel.js +3 -1
- package/package.json +1 -1
- package/src/configuration.ts +18 -11
- package/src/controller/gateway/AsyncTaskController.ts +43 -2
- package/src/controller/gateway/CrudMtdGatewayController.ts +2 -1
- package/src/controller/gateway/StaticController.ts +11 -40
- package/src/controller/manage/AccountRoleManageApi.ts +38 -0
- package/src/controller/manage/UserAccountManageApi.ts +4 -3
- package/src/libs/crud-pro/models/keys.ts +1 -0
- package/src/libs/crud-pro/services/CrudProExecuteFuncService.ts +3 -2
- package/src/libs/crud-pro/services/CrudProFieldUpdateService.ts +5 -0
- package/src/libs/crud-pro/services/CrudProTableMetaService.ts +2 -2
- package/src/libs/crud-pro/utils/DatabaseName.ts +12 -0
- package/src/libs/crud-pro/utils/DateTimeUtils.ts +1 -1
- package/src/libs/utils/functions.ts +34 -2
- package/src/service/AuthService.ts +2 -2
- package/src/service/crudstd/CrudStdService.ts +7 -3
- package/src/service/curd/fixCfgModel.ts +3 -1
package/dist/configuration.d.ts
CHANGED
package/dist/configuration.js
CHANGED
|
@@ -89,14 +89,20 @@ let ContainerLifeCycle = class ContainerLifeCycle {
|
|
|
89
89
|
* 会通过 Redis 广播通知所有节点刷新缓存。
|
|
90
90
|
*/
|
|
91
91
|
async initCacheRefreshRedis() {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
setTimeout(async () => {
|
|
93
|
+
const app = this.app;
|
|
94
|
+
const ctx = app.createAnonymousContext();
|
|
95
|
+
const redisService = await ctx.requestContext.getAsync(redis_1.RedisService);
|
|
96
|
+
try {
|
|
97
|
+
(0, CacheRefreshRedisSubscriber_1.initCacheRefreshPublishClient)(redisService);
|
|
98
|
+
(0, CacheRefreshRedisSubscriber_1.initCacheRefreshSubscriber)(redisService);
|
|
99
|
+
this.app.getLogger().info('ContainerLifeCycle ==> initCacheRefreshRedis success');
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
// Redis 未配置或不可用时,降级为单节点模式(仅刷新本节点缓存)
|
|
103
|
+
this.app.getLogger().warn('ContainerLifeCycle ==> initCacheRefreshRedis Redis不可用,降级为单节点模式:', e.message);
|
|
104
|
+
}
|
|
105
|
+
}, 1000 * 60);
|
|
100
106
|
}
|
|
101
107
|
/**
|
|
102
108
|
* 注册各类型缓存的刷新器到 CacheRefreshHub
|
|
@@ -159,10 +165,6 @@ __decorate([
|
|
|
159
165
|
(0, core_1.App)(),
|
|
160
166
|
__metadata("design:type", Object)
|
|
161
167
|
], ContainerLifeCycle.prototype, "app", void 0);
|
|
162
|
-
__decorate([
|
|
163
|
-
(0, core_1.Inject)(),
|
|
164
|
-
__metadata("design:type", redis_1.RedisService)
|
|
165
|
-
], ContainerLifeCycle.prototype, "redisService", void 0);
|
|
166
168
|
ContainerLifeCycle = __decorate([
|
|
167
169
|
(0, core_1.Configuration)({
|
|
168
170
|
// namespace: 'fatcms',
|
|
@@ -6,6 +6,7 @@ import { BaseApiController } from '../base/BaseApiController';
|
|
|
6
6
|
export declare class AsyncTaskController extends BaseApiController {
|
|
7
7
|
protected ctx: Context;
|
|
8
8
|
private asyncTaskService;
|
|
9
|
+
private crudStdService;
|
|
9
10
|
getMyTasks(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
10
11
|
createTask(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
11
12
|
cancelTask(id: number): Promise<{
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.AsyncTaskController = void 0;
|
|
16
16
|
const fs = require("fs");
|
|
17
17
|
const fs2 = require("node:fs/promises");
|
|
18
|
+
const md5 = require("md5");
|
|
18
19
|
const core_1 = require("@midwayjs/core");
|
|
19
20
|
const BaseApiController_1 = require("../base/BaseApiController");
|
|
20
21
|
const AsyncTaskService_1 = require("../../service/asyncTask/AsyncTaskService");
|
|
@@ -24,6 +25,8 @@ const SystemTables_1 = require("../../models/SystemTables");
|
|
|
24
25
|
const exceptions_1 = require("../../libs/crud-pro/exceptions");
|
|
25
26
|
const permission_middleware_1 = require("../../middleware/permission.middleware");
|
|
26
27
|
const functions_1 = require("../../libs/utils/functions");
|
|
28
|
+
const CrudStdService_1 = require("../../service/crudstd/CrudStdService");
|
|
29
|
+
const devops_1 = require("../../models/devops");
|
|
27
30
|
function fixMyTasksCondition(body, ctx) {
|
|
28
31
|
if (!body.condition) {
|
|
29
32
|
throw new exceptions_1.CommonException('参数不正确');
|
|
@@ -43,6 +46,27 @@ function fixCancelBodyData(body, id) {
|
|
|
43
46
|
dataObj.task_status = AsyncTaskModel_1.SysAsyncTaskStatus.CANCELLED;
|
|
44
47
|
body.data = dataObj;
|
|
45
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* 验证 STD_CRUD 类型的异步任务权限
|
|
51
|
+
* 根据 settingKey 配置的权限项进行鉴权
|
|
52
|
+
*/
|
|
53
|
+
async function validateStdCrudTaskPermission(crudStdService, inputParams) {
|
|
54
|
+
var _a;
|
|
55
|
+
if (inputParams.appType !== 'STD_CRUD' || !inputParams.settingKey) {
|
|
56
|
+
return; // 非 STD_CRUD 类型或无 settingKey,无需鉴权
|
|
57
|
+
}
|
|
58
|
+
const stdAction = {
|
|
59
|
+
appCode: inputParams.appCode,
|
|
60
|
+
settingKey: inputParams.settingKey,
|
|
61
|
+
};
|
|
62
|
+
const appInfo = await crudStdService.getParsedCrudStdAppForSettingKey(stdAction);
|
|
63
|
+
if (!appInfo || appInfo.status !== 1) {
|
|
64
|
+
throw new devops_1.BizException('应用不存在或已下线:' + inputParams.appCode);
|
|
65
|
+
}
|
|
66
|
+
if (!((_a = appInfo.settingKeyActionCfg) === null || _a === void 0 ? void 0 : _a.hasOperationPerm)) {
|
|
67
|
+
throw new devops_1.BizException('没有操作权限:settingKey=' + inputParams.settingKey);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
46
70
|
function fixCreateBodyData(body, ctx) {
|
|
47
71
|
if (!body.data) {
|
|
48
72
|
throw new exceptions_1.CommonException('参数不正确');
|
|
@@ -57,6 +81,11 @@ function fixCreateBodyData(body, ctx) {
|
|
|
57
81
|
host: headers.host,
|
|
58
82
|
origin: headers.origin,
|
|
59
83
|
};
|
|
84
|
+
dataObj.task_uuid = md5(JSON.stringify({
|
|
85
|
+
input_params: input_params,
|
|
86
|
+
created_by: sessionInfo.accountId,
|
|
87
|
+
created_time: Date.now(),
|
|
88
|
+
}));
|
|
60
89
|
dataObj.task_status = AsyncTaskModel_1.SysAsyncTaskStatus.PENDING;
|
|
61
90
|
dataObj.created_by = sessionInfo.accountId;
|
|
62
91
|
dataObj.created_user_session = JSON.stringify(sessionInfo); // 创建人的session信息。用于执行时的鉴权。
|
|
@@ -73,9 +102,14 @@ let AsyncTaskController = class AsyncTaskController extends BaseApiController_1.
|
|
|
73
102
|
}
|
|
74
103
|
// 创建任务
|
|
75
104
|
async createTask() {
|
|
76
|
-
|
|
105
|
+
var _a;
|
|
106
|
+
// 每个用户:5秒内只能创建1次任务
|
|
77
107
|
await this.checkUserActionTimeLimit('AsyncTaskController_createTask', 5);
|
|
78
|
-
|
|
108
|
+
// 解析 input_params 并进行权限鉴权
|
|
109
|
+
const body = this.ctx.request.body;
|
|
110
|
+
const inputParams = (0, functions_1.parseJsonObject)((_a = body.data) === null || _a === void 0 ? void 0 : _a.input_params) || {};
|
|
111
|
+
await validateStdCrudTaskPermission(this.crudStdService, inputParams);
|
|
112
|
+
fixCreateBodyData(body, this.ctx);
|
|
79
113
|
const res = await this.executeSysSimpleSQL(SystemTables_1.SystemTables.sys_async_tasks, keys_1.KeysOfSimpleSQL.SIMPLE_INSERT);
|
|
80
114
|
await this.asyncTaskService.startTask();
|
|
81
115
|
return res;
|
|
@@ -148,6 +182,10 @@ __decorate([
|
|
|
148
182
|
(0, core_1.Inject)(),
|
|
149
183
|
__metadata("design:type", AsyncTaskService_1.AsyncTaskService)
|
|
150
184
|
], AsyncTaskController.prototype, "asyncTaskService", void 0);
|
|
185
|
+
__decorate([
|
|
186
|
+
(0, core_1.Inject)(),
|
|
187
|
+
__metadata("design:type", CrudStdService_1.CrudStdService)
|
|
188
|
+
], AsyncTaskController.prototype, "crudStdService", void 0);
|
|
151
189
|
__decorate([
|
|
152
190
|
(0, core_1.Post)('/getMyTasks'),
|
|
153
191
|
__metadata("design:type", Function),
|
|
@@ -23,6 +23,7 @@ const CurdProService_1 = require("../../service/curd/CurdProService");
|
|
|
23
23
|
const CurdMixService_1 = require("../../service/curd/CurdMixService");
|
|
24
24
|
const DatabaseName_1 = require("../../libs/crud-pro/utils/DatabaseName");
|
|
25
25
|
const global_config_1 = require("../../libs/global-config/global-config");
|
|
26
|
+
const functions_1 = require("../../libs/utils/functions");
|
|
26
27
|
const QUERY_AS_LIST = ['condition', 'data'];
|
|
27
28
|
function pickAsQuery(query_as_pick, query) {
|
|
28
29
|
if (query_as_pick && typeof query_as_pick === 'string') {
|
|
@@ -48,7 +49,7 @@ let CrudMtdGatewayController = class CrudMtdGatewayController extends ApiBaseSer
|
|
|
48
49
|
return common_dto_1.CommonResult.errorRes('method参数不存在');
|
|
49
50
|
}
|
|
50
51
|
const methodInfo = (await this.curdProService.getCachedCfgByMethod(methodCode));
|
|
51
|
-
if (!methodInfo ||
|
|
52
|
+
if (!methodInfo || !(0, functions_1.isEntityOK)(methodInfo)) {
|
|
52
53
|
return common_dto_1.CommonResult.errorRes('接口不存在或已下线: ' + methodCode);
|
|
53
54
|
}
|
|
54
55
|
this.logInfo('methodInfo=== ', methodInfo);
|
|
@@ -12,10 +12,8 @@ interface HttpGetRes {
|
|
|
12
12
|
export declare class StaticController extends BaseApiController {
|
|
13
13
|
protected ctx: Context;
|
|
14
14
|
private getLocalPaths;
|
|
15
|
-
private initNotFoundList;
|
|
16
15
|
private responseLocalFile;
|
|
17
16
|
proxyStaticFile(ossName: string, relativePath: string): Promise<string>;
|
|
18
|
-
saveNotFoundList(): Promise<void>;
|
|
19
17
|
httpsGet(url: string): Promise<HttpGetRes>;
|
|
20
18
|
writeResponseToFile(httpsGetRes: HttpGetRes, localFilePath: string, localHeaderPath: string): Promise<void>;
|
|
21
19
|
getMimeType(filePath: string): any;
|
|
@@ -37,9 +37,8 @@ function getPathConfig(ossName) {
|
|
|
37
37
|
remoteBaseUrl,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
// 404
|
|
40
|
+
// 404列表缓存: 只再内存中记录。重启后继续
|
|
41
41
|
let notFoundList = new Set();
|
|
42
|
-
let notFoundListIsInit = false;
|
|
43
42
|
/**
|
|
44
43
|
* 静态文件代理功能
|
|
45
44
|
*/
|
|
@@ -48,31 +47,10 @@ let StaticController = class StaticController extends BaseApiController_1.BaseAp
|
|
|
48
47
|
const app = schedule_1.ANONYMOUS_CONTEXT.getApp();
|
|
49
48
|
const appDir = app.getAppDir();
|
|
50
49
|
const localDir = path.join(appDir, './public/static'); // 本地文件存储目录
|
|
51
|
-
const notFoundListFile = path.join(localDir, '__404__list.json'); // 404列表文件
|
|
52
50
|
return {
|
|
53
51
|
localDir,
|
|
54
|
-
notFoundListFile,
|
|
55
52
|
};
|
|
56
53
|
}
|
|
57
|
-
async initNotFoundList() {
|
|
58
|
-
if (notFoundListIsInit) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
notFoundListIsInit = true;
|
|
62
|
-
const { localDir, notFoundListFile } = this.getLocalPaths();
|
|
63
|
-
try {
|
|
64
|
-
// 确保本地存储目录存在
|
|
65
|
-
await fs.mkdir(localDir, { recursive: true });
|
|
66
|
-
const data = await fs.readFile(notFoundListFile, 'utf8');
|
|
67
|
-
notFoundList = new Set(JSON.parse(data));
|
|
68
|
-
console.log(`已加载${notFoundList.size}个404记录`);
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
if (error.code !== 'ENOENT') {
|
|
72
|
-
console.error('读取404列表失败:', error);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
54
|
async responseLocalFile(localFilePath, localHeaderPath, relativePath) {
|
|
77
55
|
const headers = {
|
|
78
56
|
'Cache-Control': 'public, max-age=31536000',
|
|
@@ -84,8 +62,10 @@ let StaticController = class StaticController extends BaseApiController_1.BaseAp
|
|
|
84
62
|
if (stats.isFile()) {
|
|
85
63
|
const headerDataStr = await fs.readFile(localHeaderPath, 'utf8');
|
|
86
64
|
const headerData = (0, functions_1.parseJsonObject)(headerDataStr);
|
|
87
|
-
if (headerData) {
|
|
65
|
+
if (headerData && headerData['last-modified']) {
|
|
88
66
|
headers['last-modified'] = headerData['last-modified'];
|
|
67
|
+
}
|
|
68
|
+
if (headerData && headerData['etag']) {
|
|
89
69
|
headers['etag'] = headerData['etag'];
|
|
90
70
|
}
|
|
91
71
|
}
|
|
@@ -117,7 +97,6 @@ let StaticController = class StaticController extends BaseApiController_1.BaseAp
|
|
|
117
97
|
return false;
|
|
118
98
|
}
|
|
119
99
|
async proxyStaticFile(ossName, relativePath) {
|
|
120
|
-
await this.initNotFoundList();
|
|
121
100
|
const { localDir } = this.getLocalPaths();
|
|
122
101
|
const PATH_CONFIG = getPathConfig(ossName);
|
|
123
102
|
// 构建本地路径和远程路径
|
|
@@ -149,7 +128,6 @@ let StaticController = class StaticController extends BaseApiController_1.BaseAp
|
|
|
149
128
|
else if (remoteRes.statusCode === 404) {
|
|
150
129
|
// 记录404并返回
|
|
151
130
|
notFoundList.add(relativePath);
|
|
152
|
-
await this.saveNotFoundList();
|
|
153
131
|
this.logInfo(`[StaticController]远程文件不存在,已记录404: ${relativePath}`);
|
|
154
132
|
this.ctx.status = 404;
|
|
155
133
|
return this.ctx.render('500', { errorMsg: ' 远程文件不存在,已记录404' });
|
|
@@ -171,19 +149,6 @@ let StaticController = class StaticController extends BaseApiController_1.BaseAp
|
|
|
171
149
|
this.ctx.status = 500;
|
|
172
150
|
return this.ctx.render('500', { errorMsg: '未知异常' });
|
|
173
151
|
}
|
|
174
|
-
// 保存404列表
|
|
175
|
-
async saveNotFoundList() {
|
|
176
|
-
const { notFoundListFile } = this.getLocalPaths();
|
|
177
|
-
try {
|
|
178
|
-
// 确保存储404列表的目录存在
|
|
179
|
-
const dir = path.dirname(notFoundListFile);
|
|
180
|
-
await fs.mkdir(dir, { recursive: true });
|
|
181
|
-
await fs.writeFile(notFoundListFile, JSON.stringify(Array.from(notFoundList), null), 'utf8');
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
this.logError('[StaticController]保存404列表失败:', error);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
152
|
// 封装https请求为异步函数
|
|
188
153
|
async httpsGet(url) {
|
|
189
154
|
return new Promise((resolve, reject) => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Context } from '@midwayjs/koa';
|
|
2
2
|
import { BaseApiController } from '../base/BaseApiController';
|
|
3
|
+
import { CommonResult } from '../../libs/utils/common-dto';
|
|
3
4
|
export declare class AccountRoleManageApi extends BaseApiController {
|
|
4
5
|
protected ctx: Context;
|
|
5
6
|
getAccountRoleList(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
6
7
|
getAccountRoleOne(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
7
|
-
createAccountRole(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
8
|
+
createAccountRole(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext | CommonResult>;
|
|
8
9
|
updateAccountRole(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
9
10
|
deleteAccountRole(): Promise<import("../../libs/crud-pro/models/ExecuteContext").ExecuteContext>;
|
|
10
11
|
}
|
|
@@ -18,6 +18,9 @@ const cacherefresh_middleware_1 = require("../../middleware/cacherefresh.middlew
|
|
|
18
18
|
const bizmodels_1 = require("../../models/bizmodels");
|
|
19
19
|
const SystemPerm_1 = require("../../models/SystemPerm");
|
|
20
20
|
const CurdMixUtils_1 = require("../../service/curd/CurdMixUtils");
|
|
21
|
+
const SystemTables_1 = require("../../models/SystemTables");
|
|
22
|
+
const global_config_1 = require("../../libs/global-config/global-config");
|
|
23
|
+
const common_dto_1 = require("../../libs/utils/common-dto");
|
|
21
24
|
let AccountRoleManageApi = class AccountRoleManageApi extends BaseApiController_1.BaseApiController {
|
|
22
25
|
async getAccountRoleList() {
|
|
23
26
|
return this.executeSysSimpleSQL('sys_perm_user_role', keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_PAGE, {
|
|
@@ -40,6 +43,37 @@ let AccountRoleManageApi = class AccountRoleManageApi extends BaseApiController_
|
|
|
40
43
|
return this.executeSysSimpleSQL('sys_perm_user_role', keys_1.KeysOfSimpleSQL.SIMPLE_QUERY_ONE);
|
|
41
44
|
}
|
|
42
45
|
async createAccountRole() {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
const { SystemDbName, SystemDbType } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
|
|
48
|
+
const body = this.ctx.request.body;
|
|
49
|
+
const accountId = (_a = body.data) === null || _a === void 0 ? void 0 : _a.account_id;
|
|
50
|
+
const roleCode = (_b = body.data) === null || _b === void 0 ? void 0 : _b.role_code;
|
|
51
|
+
// 校验 account_id 是否存在
|
|
52
|
+
if (accountId) {
|
|
53
|
+
const accountInfoRes = await this.curdMixService.getQuickCrud({
|
|
54
|
+
sqlDatabase: SystemDbName,
|
|
55
|
+
sqlDbType: SystemDbType,
|
|
56
|
+
sqlTable: SystemTables_1.SystemTables.sys_user_account,
|
|
57
|
+
}).isExist({
|
|
58
|
+
condition: { account_id: accountId }
|
|
59
|
+
});
|
|
60
|
+
if (!accountInfoRes.exists) {
|
|
61
|
+
return common_dto_1.CommonResult.errorRes(`账户ID '${accountId}' 不存在`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// 校验 role_code 是否存在
|
|
65
|
+
if (roleCode) {
|
|
66
|
+
const roleInfoRes = await this.curdMixService.getQuickCrud({
|
|
67
|
+
sqlDatabase: SystemDbName,
|
|
68
|
+
sqlDbType: SystemDbType,
|
|
69
|
+
sqlTable: SystemTables_1.SystemTables.sys_perm_role,
|
|
70
|
+
}).isExist({
|
|
71
|
+
condition: { role_code: roleCode }
|
|
72
|
+
});
|
|
73
|
+
if (!roleInfoRes.exists) {
|
|
74
|
+
return common_dto_1.CommonResult.errorRes(`角色编码 '${roleCode}' 不存在`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
43
77
|
return this.executeSysSimpleSQL('sys_perm_user_role', keys_1.KeysOfSimpleSQL.SIMPLE_INSERT, {
|
|
44
78
|
validateCfg: {
|
|
45
79
|
'data.account_id': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
|
|
@@ -13,13 +13,13 @@ exports.UserAccountManageApi = void 0;
|
|
|
13
13
|
const core_1 = require("@midwayjs/core");
|
|
14
14
|
const keys_1 = require("../../libs/crud-pro/models/keys");
|
|
15
15
|
const BaseApiController_1 = require("../base/BaseApiController");
|
|
16
|
-
const functions_1 = require("../../libs/utils/functions");
|
|
17
16
|
const permission_middleware_1 = require("../../middleware/permission.middleware");
|
|
18
17
|
const SystemPerm_1 = require("../../models/SystemPerm");
|
|
19
18
|
const exceptions_1 = require("../../libs/crud-pro/exceptions");
|
|
20
19
|
const SystemTables_1 = require("../../models/SystemTables");
|
|
21
20
|
const global_config_1 = require("../../libs/global-config/global-config");
|
|
22
21
|
const common_dto_1 = require("../../libs/utils/common-dto");
|
|
22
|
+
const MixinUtils_1 = require("../../libs/crud-pro/utils/MixinUtils");
|
|
23
23
|
const accountNameBlacklist = new Set(['sa', 'root', 'admin', 'superadmin', 'administrator', 'sys', 'sysop', 'schedule_user']);
|
|
24
24
|
function checkAccountCreateBlacklist(value) {
|
|
25
25
|
if (!value) {
|
|
@@ -73,16 +73,17 @@ let UserAccountManageApi = class UserAccountManageApi extends BaseApiController_
|
|
|
73
73
|
}
|
|
74
74
|
async createUserAccount() {
|
|
75
75
|
const body = this.ctx.request.body;
|
|
76
|
-
body.data.account_id = (0, functions_1.createUniqueId)();
|
|
77
76
|
const { generateUserAccountId } = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
|
|
78
77
|
if (typeof generateUserAccountId === 'function') {
|
|
79
78
|
body.data.account_id = await generateUserAccountId(body.data);
|
|
80
79
|
}
|
|
80
|
+
else {
|
|
81
|
+
body.data.account_id = MixinUtils_1.MixinUtils.generateSnowflakeId();
|
|
82
|
+
}
|
|
81
83
|
const result = await this.executeSysSimpleSQL(SystemTables_1.SystemTables.sys_user_account, keys_1.KeysOfSimpleSQL.SIMPLE_INSERT, {
|
|
82
84
|
validateCfg: {
|
|
83
85
|
'data.login_name': LOGIN_NAME_VALIDATE,
|
|
84
86
|
'data.nick_name': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING, 'length:2,20', checkAccountCreateBlacklist],
|
|
85
|
-
'data.avatar': [keys_1.KeysOfValidators.REQUIRED, keys_1.KeysOfValidators.STRING],
|
|
86
87
|
},
|
|
87
88
|
});
|
|
88
89
|
return result;
|
|
@@ -13,6 +13,7 @@ var KeysOfFunCtx;
|
|
|
13
13
|
KeysOfFunCtx["CURRENT_VALUE"] = "$current";
|
|
14
14
|
KeysOfFunCtx["VISITOR"] = "visitor";
|
|
15
15
|
KeysOfFunCtx["VISITOR_ATTR"] = "visitor.";
|
|
16
|
+
KeysOfFunCtx["VISITOR_AVATAR"] = "visitor.avatar";
|
|
16
17
|
KeysOfFunCtx["REQUEST"] = "req.";
|
|
17
18
|
KeysOfFunCtx["RESULT"] = "res.";
|
|
18
19
|
})(KeysOfFunCtx = exports.KeysOfFunCtx || (exports.KeysOfFunCtx = {}));
|
|
@@ -82,8 +82,8 @@ class CrudProExecuteFuncService extends CrudProServiceBase_1.CrudProServiceBase
|
|
|
82
82
|
if (pickString.startsWith(keys_1.KeysOfFunCtx.VISITOR_ATTR)) {
|
|
83
83
|
const reqModel = funcCtx === null || funcCtx === void 0 ? void 0 : funcCtx.reqModel;
|
|
84
84
|
const attrValue = _.get(reqModel, pickString); // visitor.nickName
|
|
85
|
-
if (isNil(attrValue)) {
|
|
86
|
-
throw new exceptions_1.CommonException(exceptions_1.Exceptions.RUN_PICK_ERR_VISITOR_NULL, '
|
|
85
|
+
if (isNil(attrValue) && ![`${keys_1.KeysOfFunCtx.VISITOR_AVATAR}`].includes(pickString)) {
|
|
86
|
+
throw new exceptions_1.CommonException(exceptions_1.Exceptions.RUN_PICK_ERR_VISITOR_NULL, '获取用户字段${pickString}失败, 可能用户没有登陆');
|
|
87
87
|
}
|
|
88
88
|
return attrValue;
|
|
89
89
|
}
|
|
@@ -43,6 +43,9 @@ class CrudProFieldUpdateService extends CrudProServiceBase_1.CrudProServiceBase
|
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
45
|
this.logger.error('getUpdateNewValueByCfg->executeFuncCfg', e);
|
|
46
|
+
if (e instanceof exceptions_1.CommonException) {
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
46
49
|
throw new exceptions_1.CommonException(exceptions_1.Exceptions.UPDATE_EXCEPTION, key + '.' + e);
|
|
47
50
|
}
|
|
48
51
|
return result;
|
|
@@ -142,11 +142,11 @@ class CrudProTableMetaService extends CrudProServiceBase_1.CrudProServiceBase {
|
|
|
142
142
|
async loadMySQLAllTableInfos(query) {
|
|
143
143
|
const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType };
|
|
144
144
|
// 获取物理表
|
|
145
|
-
const tableSql = `SHOW TABLES
|
|
145
|
+
const tableSql = `SHOW TABLES`;
|
|
146
146
|
const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
|
|
147
147
|
const tableNames = (tableRes.rows || []).map((row) => Object.values(row)[0]);
|
|
148
148
|
// 获取视图
|
|
149
|
-
const viewSql = `SHOW FULL TABLES
|
|
149
|
+
const viewSql = `SHOW FULL TABLES WHERE Table_type = 'VIEW'`;
|
|
150
150
|
const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
|
|
151
151
|
const viewNames = (viewRes.rows || []).map((row) => Object.values(row)[0]);
|
|
152
152
|
const tables = [
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toDatabaseNameStr = exports.parseDatabaseName = exports.SPLIT_CONST = void 0;
|
|
4
4
|
const keys_1 = require("../models/keys");
|
|
5
|
+
const global_config_1 = require("../../global-config/global-config");
|
|
5
6
|
const SPLIT_CONST = '_________';
|
|
6
7
|
exports.SPLIT_CONST = SPLIT_CONST;
|
|
7
8
|
const PREFIX_MYSQL = `${keys_1.SqlDbType.mysql}${SPLIT_CONST}`;
|
|
@@ -27,6 +28,16 @@ function parseDatabaseName(databaseName) {
|
|
|
27
28
|
dbName: dbNameArr[1],
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
const gConfig = global_config_1.GLOBAL_STATIC_CONFIG.getConfig();
|
|
32
|
+
// 访问系统库
|
|
33
|
+
if (databaseName === 'fatcms' || databaseName === gConfig.SystemDbName) {
|
|
34
|
+
if (dbNameArr.length === 1) {
|
|
35
|
+
return {
|
|
36
|
+
dbType: gConfig.SystemDbType,
|
|
37
|
+
dbName: dbNameArr[0],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
30
41
|
if (dbNameArr.length === 1) {
|
|
31
42
|
return {
|
|
32
43
|
dbType: keys_1.SqlDbType.mysql,
|
|
@@ -8,4 +8,11 @@ declare function getCurrentFullMoment(): string;
|
|
|
8
8
|
* @returns 仅包含 ASCII 字符返回 true,否则返回 false;非字符串输入返回 false
|
|
9
9
|
*/
|
|
10
10
|
declare function isOnlyAscii(str: string): boolean;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* 如果entity不存在删除属性或属性为0,表示未删除
|
|
13
|
+
* @param entity
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
declare function isEntityDeleted(entity: any): boolean;
|
|
17
|
+
declare function isEntityOK(entity: any): boolean;
|
|
18
|
+
export { createUniqueId, parseJsonObject, parseStringTrimArray, getCurrentFullMoment, isOnlyAscii, isEntityDeleted, isEntityOK };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isOnlyAscii = exports.getCurrentFullMoment = exports.parseStringTrimArray = exports.parseJsonObject = exports.createUniqueId = void 0;
|
|
3
|
+
exports.isEntityOK = exports.isEntityDeleted = exports.isOnlyAscii = exports.getCurrentFullMoment = exports.parseStringTrimArray = exports.parseJsonObject = exports.createUniqueId = void 0;
|
|
4
4
|
const md5 = require("md5");
|
|
5
5
|
const moment = require("moment");
|
|
6
6
|
let createUniqueIdIndex = 0;
|
|
@@ -97,3 +97,28 @@ function isOnlyAscii(str) {
|
|
|
97
97
|
return true;
|
|
98
98
|
}
|
|
99
99
|
exports.isOnlyAscii = isOnlyAscii;
|
|
100
|
+
/**
|
|
101
|
+
* 如果entity不存在删除属性或属性为0,表示未删除
|
|
102
|
+
* @param entity
|
|
103
|
+
* @returns
|
|
104
|
+
*/
|
|
105
|
+
function isEntityDeleted(entity) {
|
|
106
|
+
if (!entity) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const deletedAt = Number(entity.deleted_at);
|
|
110
|
+
if (deletedAt && deletedAt > 0) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
const deletedAt2 = Number(entity.deletedAt);
|
|
114
|
+
if (deletedAt2 && deletedAt2 > 0) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
exports.isEntityDeleted = isEntityDeleted;
|
|
120
|
+
function isEntityOK(entity) {
|
|
121
|
+
const isOK = (entity === null || entity === void 0 ? void 0 : entity.status) === 1 || (entity === null || entity === void 0 ? void 0 : entity.status) === '1';
|
|
122
|
+
return isOK && !isEntityDeleted(entity);
|
|
123
|
+
}
|
|
124
|
+
exports.isEntityOK = isEntityOK;
|
|
@@ -119,7 +119,7 @@ let AuthService = class AuthService extends BaseService_1.BaseService {
|
|
|
119
119
|
const { publicKey, privateKey } = await AsymmetricCrypto_1.AsymmetricCrypto.generateKeyPair();
|
|
120
120
|
const sessionInfo = {
|
|
121
121
|
nickName: userAccount.nick_name,
|
|
122
|
-
avatar: userAccount.avatar,
|
|
122
|
+
avatar: userAccount.avatar || "",
|
|
123
123
|
roleCodes,
|
|
124
124
|
functionCodes,
|
|
125
125
|
loginName,
|
|
@@ -2,7 +2,7 @@ import { Context } from '@midwayjs/koa';
|
|
|
2
2
|
import { CurdMixService } from '../curd/CurdMixService';
|
|
3
3
|
import { IRequestModel } from '../../libs/crud-pro/interfaces';
|
|
4
4
|
import { KeysOfSimpleSQL } from '../../libs/crud-pro/models/keys';
|
|
5
|
-
import { ICrudStdAppInfo } from '../../models/bizmodels';
|
|
5
|
+
import { ICrudStdAppInfo, ICrudStdAppInfoForSettingKey } from '../../models/bizmodels';
|
|
6
6
|
import { ExecuteContext } from '../../libs/crud-pro/models/ExecuteContext';
|
|
7
7
|
import { CrudStdActionService } from './CrudStdActionService';
|
|
8
8
|
import { CrudStdRelationService } from './CrudStdRelationService';
|
|
@@ -37,9 +37,8 @@ export declare class CrudStdService extends ApiBaseService {
|
|
|
37
37
|
* 获取appInfo 并且拿到当前settingKey相关的信息
|
|
38
38
|
* @param appCode
|
|
39
39
|
* @param settingKey
|
|
40
|
-
* @private
|
|
41
40
|
*/
|
|
42
|
-
|
|
41
|
+
getParsedCrudStdAppForSettingKey(stdAction: ICrudStdActionParams): Promise<ICrudStdAppInfoForSettingKey>;
|
|
43
42
|
/**
|
|
44
43
|
* 执行动作
|
|
45
44
|
* @param stdAction
|
|
@@ -68,6 +68,9 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
68
68
|
const stdCrudCfgObj = appInfo.stdCrudCfgObj;
|
|
69
69
|
//删除策略
|
|
70
70
|
const deleteStrategy = _.get(stdCrudCfgObj, 'othersSetting.values.deleteStrategy');
|
|
71
|
+
// 自动
|
|
72
|
+
const enableStandardUpdateCfg = _.get(stdCrudCfgObj, 'othersSetting.values.enableStandardUpdateCfg');
|
|
73
|
+
const enableStandardUpdateCfgCondition = _.get(stdCrudCfgObj, 'othersSetting.values.enableStandardUpdateCfgCondition');
|
|
71
74
|
const databaseName = stdCrudCfgObj.tableBaseInfo.databaseName;
|
|
72
75
|
const { dbType, dbName } = (0, DatabaseName_1.parseDatabaseName)(databaseName);
|
|
73
76
|
const cfgModel = {
|
|
@@ -76,7 +79,9 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
76
79
|
sqlTable: getExecuteTableNameBySettingKey(appInfo, stdAction, sqlSimpleName),
|
|
77
80
|
sqlSimpleName,
|
|
78
81
|
updateCfg: {},
|
|
79
|
-
enableSoftDelete: deleteStrategy === 'soft'
|
|
82
|
+
enableSoftDelete: deleteStrategy === 'soft',
|
|
83
|
+
enableStandardUpdateCfg: Array.isArray(enableStandardUpdateCfg) && enableStandardUpdateCfg.length > 0 ? enableStandardUpdateCfg : ['by', 'at'],
|
|
84
|
+
enableStandardUpdateCfgCondition: Array.isArray(enableStandardUpdateCfgCondition) && enableStandardUpdateCfgCondition.length > 0 ? enableStandardUpdateCfgCondition : false, // 默认为false
|
|
80
85
|
};
|
|
81
86
|
// 接口返回最大值
|
|
82
87
|
const maxLimit = _.get(stdCrudCfgObj, 'othersSetting.values.maxLimit');
|
|
@@ -152,7 +157,6 @@ let CrudStdService = class CrudStdService extends ApiBaseService_1.ApiBaseServic
|
|
|
152
157
|
* 获取appInfo 并且拿到当前settingKey相关的信息
|
|
153
158
|
* @param appCode
|
|
154
159
|
* @param settingKey
|
|
155
|
-
* @private
|
|
156
160
|
*/
|
|
157
161
|
async getParsedCrudStdAppForSettingKey(stdAction) {
|
|
158
162
|
const { appCode, settingKey, buttonSettingKey } = stdAction || {};
|
|
@@ -30,7 +30,7 @@ function fixCfgModel(cfgModel) {
|
|
|
30
30
|
return enableStandardUpdateCfg;
|
|
31
31
|
}
|
|
32
32
|
// update 、insert 添加 by
|
|
33
|
-
return ['by']; // 创建/修改语句默认添加by
|
|
33
|
+
return ['by', 'at']; // 创建/修改语句默认添加by
|
|
34
34
|
};
|
|
35
35
|
const getConditionCfgArray = () => {
|
|
36
36
|
// 明确有配置
|
|
@@ -47,10 +47,12 @@ function fixCfgModel(cfgModel) {
|
|
|
47
47
|
const mapping = {
|
|
48
48
|
'condition.created_by': { contextAsString: bizmodels_1.CTX_VISITOR_ID },
|
|
49
49
|
'condition.created_account_type': { contextAsString: bizmodels_1.CTX_VISITOR_ACCOUNT_TYPE },
|
|
50
|
+
'data.created_at': { functionName: 'getCurrentTimeString' },
|
|
50
51
|
'data.created_by': { contextAsString: bizmodels_1.CTX_VISITOR_ID },
|
|
51
52
|
'data.created_avatar': { contextAsString: bizmodels_1.CTX_VISITOR_AVATAR },
|
|
52
53
|
'data.created_nickname': { contextAsString: bizmodels_1.CTX_VISITOR_NICKNAME },
|
|
53
54
|
'data.created_account_type': { contextAsString: bizmodels_1.CTX_VISITOR_ACCOUNT_TYPE },
|
|
55
|
+
'data.modified_at': { functionName: 'getCurrentTimeString' },
|
|
54
56
|
'data.modified_by': { contextAsString: bizmodels_1.CTX_VISITOR_ID },
|
|
55
57
|
'data.modified_avatar': { contextAsString: bizmodels_1.CTX_VISITOR_AVATAR },
|
|
56
58
|
'data.modified_nickname': { contextAsString: bizmodels_1.CTX_VISITOR_NICKNAME },
|
package/package.json
CHANGED
package/src/configuration.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Configuration, App
|
|
1
|
+
import { Configuration, App } from '@midwayjs/core';
|
|
2
2
|
import * as koa from '@midwayjs/koa';
|
|
3
3
|
import * as validate from '@midwayjs/validate';
|
|
4
4
|
import * as info from '@midwayjs/info';
|
|
@@ -45,9 +45,6 @@ export class ContainerLifeCycle {
|
|
|
45
45
|
@App()
|
|
46
46
|
app: koa.Application;
|
|
47
47
|
|
|
48
|
-
@Inject()
|
|
49
|
-
redisService: RedisService;
|
|
50
|
-
|
|
51
48
|
async onConfigLoad(): Promise<any> {
|
|
52
49
|
const config = this.app.getConfig();
|
|
53
50
|
const logger = this.app.getLogger();
|
|
@@ -110,13 +107,23 @@ export class ContainerLifeCycle {
|
|
|
110
107
|
* 会通过 Redis 广播通知所有节点刷新缓存。
|
|
111
108
|
*/
|
|
112
109
|
private async initCacheRefreshRedis() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
110
|
+
setTimeout(async () => {
|
|
111
|
+
|
|
112
|
+
const app = this.app;
|
|
113
|
+
const ctx: koa.IMidwayKoaContext = app.createAnonymousContext();
|
|
114
|
+
const redisService = await ctx.requestContext.getAsync(RedisService);
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
initCacheRefreshPublishClient(redisService);
|
|
118
|
+
initCacheRefreshSubscriber(redisService);
|
|
119
|
+
this.app.getLogger().info('ContainerLifeCycle ==> initCacheRefreshRedis success');
|
|
120
|
+
} catch (e) {
|
|
121
|
+
// Redis 未配置或不可用时,降级为单节点模式(仅刷新本节点缓存)
|
|
122
|
+
this.app.getLogger().warn('ContainerLifeCycle ==> initCacheRefreshRedis Redis不可用,降级为单节点模式:', e.message);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}, 1000 * 60);
|
|
126
|
+
|
|
120
127
|
}
|
|
121
128
|
|
|
122
129
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as fs2 from 'node:fs/promises';
|
|
3
|
+
import * as md5 from 'md5';
|
|
3
4
|
import { Controller, Inject, Post, Query, Get } from '@midwayjs/core';
|
|
4
5
|
import { Context } from '@midwayjs/koa';
|
|
5
6
|
import { BaseApiController } from '../base/BaseApiController';
|
|
@@ -10,6 +11,8 @@ import { SystemTables } from '@/models/SystemTables';
|
|
|
10
11
|
import { CommonException } from '@/libs/crud-pro/exceptions';
|
|
11
12
|
import { checkLogin } from '@/middleware/permission.middleware';
|
|
12
13
|
import { parseJsonObject } from '@/libs/utils/functions';
|
|
14
|
+
import { CrudStdService, ICrudStdActionParams } from '@/service/crudstd/CrudStdService';
|
|
15
|
+
import { BizException } from '@/models/devops';
|
|
13
16
|
|
|
14
17
|
function fixMyTasksCondition(body: any, ctx: Context) {
|
|
15
18
|
if (!body.condition) {
|
|
@@ -34,6 +37,31 @@ function fixCancelBodyData(body: any, id: number) {
|
|
|
34
37
|
body.data = dataObj;
|
|
35
38
|
}
|
|
36
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 验证 STD_CRUD 类型的异步任务权限
|
|
42
|
+
* 根据 settingKey 配置的权限项进行鉴权
|
|
43
|
+
*/
|
|
44
|
+
async function validateStdCrudTaskPermission(
|
|
45
|
+
crudStdService: CrudStdService,
|
|
46
|
+
inputParams: any
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
if (inputParams.appType !== 'STD_CRUD' || !inputParams.settingKey) {
|
|
49
|
+
return; // 非 STD_CRUD 类型或无 settingKey,无需鉴权
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const stdAction: ICrudStdActionParams = {
|
|
53
|
+
appCode: inputParams.appCode,
|
|
54
|
+
settingKey: inputParams.settingKey,
|
|
55
|
+
};
|
|
56
|
+
const appInfo = await crudStdService.getParsedCrudStdAppForSettingKey(stdAction);
|
|
57
|
+
if (!appInfo || appInfo.status !== 1) {
|
|
58
|
+
throw new BizException('应用不存在或已下线:' + inputParams.appCode);
|
|
59
|
+
}
|
|
60
|
+
if (!appInfo.settingKeyActionCfg?.hasOperationPerm) {
|
|
61
|
+
throw new BizException('没有操作权限:settingKey=' + inputParams.settingKey);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
37
65
|
function fixCreateBodyData(body: any, ctx: Context) {
|
|
38
66
|
if (!body.data) {
|
|
39
67
|
throw new CommonException('参数不正确');
|
|
@@ -49,6 +77,11 @@ function fixCreateBodyData(body: any, ctx: Context) {
|
|
|
49
77
|
host: headers.host,
|
|
50
78
|
origin: headers.origin,
|
|
51
79
|
};
|
|
80
|
+
dataObj.task_uuid = md5(JSON.stringify({
|
|
81
|
+
input_params: input_params,
|
|
82
|
+
created_by: sessionInfo.accountId,
|
|
83
|
+
created_time: Date.now(),
|
|
84
|
+
}));
|
|
52
85
|
dataObj.task_status = SysAsyncTaskStatus.PENDING;
|
|
53
86
|
dataObj.created_by = sessionInfo.accountId;
|
|
54
87
|
dataObj.created_user_session = JSON.stringify(sessionInfo); // 创建人的session信息。用于执行时的鉴权。
|
|
@@ -66,6 +99,9 @@ export class AsyncTaskController extends BaseApiController {
|
|
|
66
99
|
@Inject()
|
|
67
100
|
private asyncTaskService: AsyncTaskService;
|
|
68
101
|
|
|
102
|
+
@Inject()
|
|
103
|
+
private crudStdService: CrudStdService;
|
|
104
|
+
|
|
69
105
|
// 获取任务列表
|
|
70
106
|
@Post('/getMyTasks')
|
|
71
107
|
async getMyTasks() {
|
|
@@ -76,10 +112,15 @@ export class AsyncTaskController extends BaseApiController {
|
|
|
76
112
|
// 创建任务
|
|
77
113
|
@Post('/createTask')
|
|
78
114
|
async createTask() {
|
|
79
|
-
|
|
115
|
+
// 每个用户:5秒内只能创建1次任务
|
|
80
116
|
await this.checkUserActionTimeLimit('AsyncTaskController_createTask', 5);
|
|
81
117
|
|
|
82
|
-
|
|
118
|
+
// 解析 input_params 并进行权限鉴权
|
|
119
|
+
const body = this.ctx.request.body as any;
|
|
120
|
+
const inputParams = parseJsonObject(body.data?.input_params) || {};
|
|
121
|
+
await validateStdCrudTaskPermission(this.crudStdService, inputParams);
|
|
122
|
+
|
|
123
|
+
fixCreateBodyData(body, this.ctx);
|
|
83
124
|
const res = await this.executeSysSimpleSQL(SystemTables.sys_async_tasks, KeysOfSimpleSQL.SIMPLE_INSERT);
|
|
84
125
|
await this.asyncTaskService.startTask();
|
|
85
126
|
return res;
|
|
@@ -10,6 +10,7 @@ import { CurdMixService } from '@/service/curd/CurdMixService';
|
|
|
10
10
|
import { IRequestCfgModel2 } from '@/models/bizmodels';
|
|
11
11
|
import { parseDatabaseName } from '@/libs/crud-pro/utils/DatabaseName';
|
|
12
12
|
import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
|
|
13
|
+
import { isEntityOK } from '@/libs/utils/functions';
|
|
13
14
|
|
|
14
15
|
const QUERY_AS_LIST = ['condition', 'data'];
|
|
15
16
|
|
|
@@ -53,7 +54,7 @@ export class CrudMtdGatewayController extends ApiBaseService {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
const methodInfo = (await this.curdProService.getCachedCfgByMethod(methodCode)) as any;
|
|
56
|
-
if (!methodInfo || methodInfo
|
|
57
|
+
if (!methodInfo || !isEntityOK(methodInfo)) {
|
|
57
58
|
return CommonResult.errorRes('接口不存在或已下线: ' + methodCode);
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -31,9 +31,8 @@ function getPathConfig(ossName: string) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// 404
|
|
34
|
+
// 404列表缓存: 只再内存中记录。重启后继续
|
|
35
35
|
let notFoundList = new Set();
|
|
36
|
-
let notFoundListIsInit = false;
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* 静态文件代理功能
|
|
@@ -47,33 +46,11 @@ export class StaticController extends BaseApiController {
|
|
|
47
46
|
const app = ANONYMOUS_CONTEXT.getApp();
|
|
48
47
|
const appDir = app.getAppDir();
|
|
49
48
|
const localDir = path.join(appDir, './public/static'); // 本地文件存储目录
|
|
50
|
-
const notFoundListFile = path.join(localDir, '__404__list.json'); // 404列表文件
|
|
51
49
|
return {
|
|
52
50
|
localDir,
|
|
53
|
-
notFoundListFile,
|
|
54
51
|
};
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
private async initNotFoundList() {
|
|
58
|
-
if (notFoundListIsInit) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
notFoundListIsInit = true;
|
|
62
|
-
|
|
63
|
-
const { localDir, notFoundListFile } = this.getLocalPaths();
|
|
64
|
-
try {
|
|
65
|
-
// 确保本地存储目录存在
|
|
66
|
-
await fs.mkdir(localDir, { recursive: true });
|
|
67
|
-
const data = await fs.readFile(notFoundListFile, 'utf8');
|
|
68
|
-
|
|
69
|
-
notFoundList = new Set(JSON.parse(data));
|
|
70
|
-
console.log(`已加载${notFoundList.size}个404记录`);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
if (error.code !== 'ENOENT') {
|
|
73
|
-
console.error('读取404列表失败:', error);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
54
|
|
|
78
55
|
private async responseLocalFile(localFilePath: string, localHeaderPath: string, relativePath: string): Promise<boolean> {
|
|
79
56
|
const headers = {
|
|
@@ -87,13 +64,18 @@ export class StaticController extends BaseApiController {
|
|
|
87
64
|
if (stats.isFile()) {
|
|
88
65
|
const headerDataStr = await fs.readFile(localHeaderPath, 'utf8');
|
|
89
66
|
const headerData = parseJsonObject(headerDataStr);
|
|
90
|
-
|
|
67
|
+
|
|
68
|
+
if (headerData && headerData['last-modified']) {
|
|
91
69
|
headers['last-modified'] = headerData['last-modified'];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (headerData && headerData['etag']) {
|
|
92
73
|
headers['etag'] = headerData['etag'];
|
|
93
74
|
}
|
|
75
|
+
|
|
94
76
|
}
|
|
95
77
|
} catch (error) {
|
|
96
|
-
this.logDebug('[StaticController]responseLocalFile not found header file => ' + localHeaderPath
|
|
78
|
+
this.logDebug('[StaticController]responseLocalFile not found header file => ' + localHeaderPath);
|
|
97
79
|
}
|
|
98
80
|
|
|
99
81
|
try {
|
|
@@ -125,7 +107,7 @@ export class StaticController extends BaseApiController {
|
|
|
125
107
|
|
|
126
108
|
@All('/:ossName/:relativePath+')
|
|
127
109
|
async proxyStaticFile(@Param('ossName') ossName: string, @Param('relativePath') relativePath: string) {
|
|
128
|
-
|
|
110
|
+
|
|
129
111
|
const { localDir } = this.getLocalPaths();
|
|
130
112
|
const PATH_CONFIG = getPathConfig(ossName);
|
|
131
113
|
|
|
@@ -161,9 +143,10 @@ export class StaticController extends BaseApiController {
|
|
|
161
143
|
return;
|
|
162
144
|
}
|
|
163
145
|
} else if (remoteRes.statusCode === 404) {
|
|
146
|
+
|
|
164
147
|
// 记录404并返回
|
|
165
148
|
notFoundList.add(relativePath);
|
|
166
|
-
|
|
149
|
+
|
|
167
150
|
this.logInfo(`[StaticController]远程文件不存在,已记录404: ${relativePath}`);
|
|
168
151
|
this.ctx.status = 404;
|
|
169
152
|
return this.ctx.render('500', { errorMsg: ' 远程文件不存在,已记录404' });
|
|
@@ -185,19 +168,7 @@ export class StaticController extends BaseApiController {
|
|
|
185
168
|
return this.ctx.render('500', { errorMsg: '未知异常' });
|
|
186
169
|
}
|
|
187
170
|
|
|
188
|
-
// 保存404列表
|
|
189
|
-
async saveNotFoundList() {
|
|
190
|
-
const { notFoundListFile } = this.getLocalPaths();
|
|
191
|
-
try {
|
|
192
|
-
// 确保存储404列表的目录存在
|
|
193
|
-
const dir = path.dirname(notFoundListFile);
|
|
194
|
-
await fs.mkdir(dir, { recursive: true });
|
|
195
171
|
|
|
196
|
-
await fs.writeFile(notFoundListFile, JSON.stringify(Array.from(notFoundList), null), 'utf8');
|
|
197
|
-
} catch (error) {
|
|
198
|
-
this.logError('[StaticController]保存404列表失败:', error);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
172
|
|
|
202
173
|
// 封装https请求为异步函数
|
|
203
174
|
async httpsGet(url: string): Promise<HttpGetRes> {
|
|
@@ -7,6 +7,9 @@ import { refreshCache } from '@/middleware/cacherefresh.middleware';
|
|
|
7
7
|
import { CacheNameEnum } from '@/models/bizmodels';
|
|
8
8
|
import { SystemFuncCode } from '@/models/SystemPerm';
|
|
9
9
|
import { RelatedType } from '@/service/curd/CurdMixUtils';
|
|
10
|
+
import { SystemTables } from '@/models/SystemTables';
|
|
11
|
+
import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
|
|
12
|
+
import { CommonResult } from '@/libs/utils/common-dto';
|
|
10
13
|
|
|
11
14
|
@Controller('/ns/api/manage/accountRole', { middleware: [checkPermission(SystemFuncCode.AccountRoleManageRead)] })
|
|
12
15
|
export class AccountRoleManageApi extends BaseApiController {
|
|
@@ -39,6 +42,41 @@ export class AccountRoleManageApi extends BaseApiController {
|
|
|
39
42
|
|
|
40
43
|
@Post('/createAccountRole', { middleware: [checkPermission(SystemFuncCode.AccountRoleManageWrite), refreshCache(CacheNameEnum.CurdMixByAccount)] })
|
|
41
44
|
async createAccountRole() {
|
|
45
|
+
const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
|
|
46
|
+
const body = this.ctx.request.body as any;
|
|
47
|
+
const accountId = body.data?.account_id;
|
|
48
|
+
const roleCode = body.data?.role_code;
|
|
49
|
+
|
|
50
|
+
// 校验 account_id 是否存在
|
|
51
|
+
if (accountId) {
|
|
52
|
+
const accountInfoRes = await this.curdMixService.getQuickCrud({
|
|
53
|
+
sqlDatabase: SystemDbName,
|
|
54
|
+
sqlDbType: SystemDbType,
|
|
55
|
+
sqlTable: SystemTables.sys_user_account,
|
|
56
|
+
}).isExist({
|
|
57
|
+
condition: { account_id: accountId }
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!accountInfoRes.exists) {
|
|
61
|
+
return CommonResult.errorRes(`账户ID '${accountId}' 不存在`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 校验 role_code 是否存在
|
|
66
|
+
if (roleCode) {
|
|
67
|
+
const roleInfoRes = await this.curdMixService.getQuickCrud({
|
|
68
|
+
sqlDatabase: SystemDbName,
|
|
69
|
+
sqlDbType: SystemDbType,
|
|
70
|
+
sqlTable: SystemTables.sys_perm_role,
|
|
71
|
+
}).isExist({
|
|
72
|
+
condition: { role_code: roleCode }
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!roleInfoRes.exists) {
|
|
76
|
+
return CommonResult.errorRes(`角色编码 '${roleCode}' 不存在`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
42
80
|
return this.executeSysSimpleSQL('sys_perm_user_role', KeysOfSimpleSQL.SIMPLE_INSERT, {
|
|
43
81
|
validateCfg: {
|
|
44
82
|
'data.account_id': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
|
|
@@ -2,13 +2,13 @@ import { Controller, Inject, Post } from '@midwayjs/core';
|
|
|
2
2
|
import { Context } from '@midwayjs/koa';
|
|
3
3
|
import { KeysOfSimpleSQL, KeysOfValidators } from '../../libs/crud-pro/models/keys';
|
|
4
4
|
import { BaseApiController } from '../base/BaseApiController';
|
|
5
|
-
import { createUniqueId } from '../../libs/utils/functions';
|
|
6
5
|
import { checkPermission } from '../../middleware/permission.middleware';
|
|
7
6
|
import { SystemFuncCode } from '../../models/SystemPerm';
|
|
8
7
|
import { CommonException, Exceptions } from '../../libs/crud-pro/exceptions';
|
|
9
8
|
import { SystemTables } from '../../models/SystemTables';
|
|
10
9
|
import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
|
|
11
10
|
import { CommonResult } from "@/libs/utils/common-dto";
|
|
11
|
+
import { MixinUtils } from '@/libs/crud-pro/utils/MixinUtils';
|
|
12
12
|
|
|
13
13
|
const accountNameBlacklist = new Set(['sa', 'root', 'admin', 'superadmin', 'administrator', 'sys', 'sysop', 'schedule_user']);
|
|
14
14
|
function checkAccountCreateBlacklist(value: string) {
|
|
@@ -80,23 +80,24 @@ export class UserAccountManageApi extends BaseApiController {
|
|
|
80
80
|
@Post('/createUserAccount', { middleware: [checkPermission(SystemFuncCode.UserAccountMangeWrite)] })
|
|
81
81
|
async createUserAccount() {
|
|
82
82
|
const body = this.ctx.request.body as any;
|
|
83
|
-
body.data.account_id = createUniqueId();
|
|
84
83
|
|
|
85
84
|
const { generateUserAccountId } = GLOBAL_STATIC_CONFIG.getConfig();
|
|
86
85
|
if (typeof generateUserAccountId === 'function') {
|
|
87
86
|
body.data.account_id = await generateUserAccountId(body.data);
|
|
87
|
+
} else {
|
|
88
|
+
body.data.account_id = MixinUtils.generateSnowflakeId();
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
const result = await this.executeSysSimpleSQL(SystemTables.sys_user_account, KeysOfSimpleSQL.SIMPLE_INSERT, {
|
|
91
92
|
validateCfg: {
|
|
92
93
|
'data.login_name': LOGIN_NAME_VALIDATE,
|
|
93
94
|
'data.nick_name': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING, 'length:2,20', checkAccountCreateBlacklist],
|
|
94
|
-
'data.avatar': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
|
|
95
95
|
},
|
|
96
96
|
});
|
|
97
97
|
return result;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
|
|
100
101
|
@Post('/deleteUserAccount', { middleware: [checkPermission(SystemFuncCode.UserAccountMangeWrite)] })
|
|
101
102
|
async deleteUserAccount() {
|
|
102
103
|
const result = await this.executeSysSimpleSQL(SystemTables.sys_user_account, KeysOfSimpleSQL.SIMPLE_DELETE, {
|
|
@@ -95,8 +95,9 @@ class CrudProExecuteFuncService extends CrudProServiceBase {
|
|
|
95
95
|
if (pickString.startsWith(KeysOfFunCtx.VISITOR_ATTR)) {
|
|
96
96
|
const reqModel = funcCtx?.reqModel;
|
|
97
97
|
const attrValue = _.get(reqModel, pickString); // visitor.nickName
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
|
|
99
|
+
if (isNil(attrValue) && ![`${KeysOfFunCtx.VISITOR_AVATAR}`].includes(pickString)) {
|
|
100
|
+
throw new CommonException(Exceptions.RUN_PICK_ERR_VISITOR_NULL, '获取用户字段${pickString}失败, 可能用户没有登陆');
|
|
100
101
|
}
|
|
101
102
|
return attrValue;
|
|
102
103
|
}
|
|
@@ -49,7 +49,12 @@ class CrudProFieldUpdateService extends CrudProServiceBase {
|
|
|
49
49
|
|
|
50
50
|
result = this.serviceHub.executeFuncCfg(updateCfg, exeFunCtx);
|
|
51
51
|
} catch (e) {
|
|
52
|
+
|
|
52
53
|
this.logger.error('getUpdateNewValueByCfg->executeFuncCfg', e);
|
|
54
|
+
if (e instanceof CommonException) {
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
throw new CommonException(Exceptions.UPDATE_EXCEPTION, key + '.' + e);
|
|
54
59
|
}
|
|
55
60
|
|
|
@@ -166,12 +166,12 @@ class CrudProTableMetaService extends CrudProServiceBase {
|
|
|
166
166
|
const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType } as IExecuteUnsafeQueryCtx;
|
|
167
167
|
|
|
168
168
|
// 获取物理表
|
|
169
|
-
const tableSql = `SHOW TABLES
|
|
169
|
+
const tableSql = `SHOW TABLES`;
|
|
170
170
|
const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
|
|
171
171
|
const tableNames: string[] = (tableRes.rows || []).map((row: any) => Object.values(row)[0] as string);
|
|
172
172
|
|
|
173
173
|
// 获取视图
|
|
174
|
-
const viewSql = `SHOW FULL TABLES
|
|
174
|
+
const viewSql = `SHOW FULL TABLES WHERE Table_type = 'VIEW'`;
|
|
175
175
|
const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
|
|
176
176
|
const viewNames: string[] = (viewRes.rows || []).map((row: any) => Object.values(row)[0] as string);
|
|
177
177
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SqlDbType } from '../models/keys';
|
|
2
|
+
import { GLOBAL_STATIC_CONFIG } from '../../global-config/global-config'
|
|
2
3
|
|
|
3
4
|
interface IDbTypeAndName {
|
|
4
5
|
dbType: SqlDbType;
|
|
@@ -35,6 +36,17 @@ function parseDatabaseName(databaseName: string): IDbTypeAndName {
|
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
const gConfig = GLOBAL_STATIC_CONFIG.getConfig();
|
|
40
|
+
// 访问系统库
|
|
41
|
+
if (databaseName === 'fatcms' || databaseName === gConfig.SystemDbName) {
|
|
42
|
+
if (dbNameArr.length === 1) {
|
|
43
|
+
return {
|
|
44
|
+
dbType: gConfig.SystemDbType,
|
|
45
|
+
dbName: dbNameArr[0],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
if (dbNameArr.length === 1) {
|
|
39
51
|
return {
|
|
40
52
|
dbType: SqlDbType.mysql, // 默认
|
|
@@ -7,7 +7,7 @@ function createUniqueId(): string {
|
|
|
7
7
|
if (createUniqueIdIndex > Date.now()) {
|
|
8
8
|
createUniqueIdIndex = 0;
|
|
9
9
|
}
|
|
10
|
-
const p1 = md5(Date.now() + '' + Math.random() + '_' + createUniqueIdIndex + '_' +
|
|
10
|
+
const p1 = md5(Date.now() + '' + Math.random() + '_' + createUniqueIdIndex + '_' + Math.random());
|
|
11
11
|
const p2 = `${Date.now().toString(32)}`.padStart(10, '0');
|
|
12
12
|
const p3 = `${createUniqueIdIndex.toString(32)}`.padStart(10, '0');
|
|
13
13
|
return p1 + p2 + p3;
|
|
@@ -106,4 +106,36 @@ function isOnlyAscii(str: string): boolean {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
/**
|
|
110
|
+
* 如果entity不存在删除属性或属性为0,表示未删除
|
|
111
|
+
* @param entity
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
114
|
+
function isEntityDeleted(entity: any): boolean {
|
|
115
|
+
if (!entity) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const deletedAt = Number(entity.deleted_at);
|
|
120
|
+
if (deletedAt && deletedAt > 0) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const deletedAt2 = Number(entity.deletedAt);
|
|
125
|
+
if (deletedAt2 && deletedAt2 > 0) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
function isEntityOK(entity: any): boolean {
|
|
133
|
+
const isOK = entity?.status === 1 || entity?.status === '1';
|
|
134
|
+
return isOK && !isEntityDeleted(entity);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
export { createUniqueId, parseJsonObject, parseStringTrimArray, getCurrentFullMoment, isOnlyAscii, isEntityDeleted, isEntityOK };
|
|
@@ -142,8 +142,8 @@ export class AuthService extends BaseService {
|
|
|
142
142
|
const { publicKey, privateKey } = await AsymmetricCrypto.generateKeyPair();
|
|
143
143
|
|
|
144
144
|
const sessionInfo: ISessionInfo = {
|
|
145
|
-
nickName: userAccount.nick_name,
|
|
146
|
-
avatar: userAccount.avatar,
|
|
145
|
+
nickName: userAccount.nick_name ,
|
|
146
|
+
avatar: userAccount.avatar || "",
|
|
147
147
|
roleCodes,
|
|
148
148
|
functionCodes,
|
|
149
149
|
loginName,
|
|
@@ -103,6 +103,9 @@ export class CrudStdService extends ApiBaseService {
|
|
|
103
103
|
|
|
104
104
|
//删除策略
|
|
105
105
|
const deleteStrategy = _.get(stdCrudCfgObj, 'othersSetting.values.deleteStrategy');
|
|
106
|
+
// 自动
|
|
107
|
+
const enableStandardUpdateCfg: string[] = _.get(stdCrudCfgObj, 'othersSetting.values.enableStandardUpdateCfg');
|
|
108
|
+
const enableStandardUpdateCfgCondition: string[] = _.get(stdCrudCfgObj, 'othersSetting.values.enableStandardUpdateCfgCondition');
|
|
106
109
|
|
|
107
110
|
const databaseName = stdCrudCfgObj.tableBaseInfo.databaseName;
|
|
108
111
|
|
|
@@ -114,7 +117,9 @@ export class CrudStdService extends ApiBaseService {
|
|
|
114
117
|
sqlTable: getExecuteTableNameBySettingKey(appInfo, stdAction, sqlSimpleName),
|
|
115
118
|
sqlSimpleName,
|
|
116
119
|
updateCfg: {},
|
|
117
|
-
enableSoftDelete: deleteStrategy === 'soft' // 软删除
|
|
120
|
+
enableSoftDelete: deleteStrategy === 'soft', // 软删除
|
|
121
|
+
enableStandardUpdateCfg: Array.isArray(enableStandardUpdateCfg) && enableStandardUpdateCfg.length > 0 ? enableStandardUpdateCfg : ['by', 'at'], // 默认为 ['by', 'at']
|
|
122
|
+
enableStandardUpdateCfgCondition: Array.isArray(enableStandardUpdateCfgCondition) && enableStandardUpdateCfgCondition.length > 0 ? enableStandardUpdateCfgCondition : false, // 默认为false
|
|
118
123
|
};
|
|
119
124
|
|
|
120
125
|
// 接口返回最大值
|
|
@@ -216,9 +221,8 @@ export class CrudStdService extends ApiBaseService {
|
|
|
216
221
|
* 获取appInfo 并且拿到当前settingKey相关的信息
|
|
217
222
|
* @param appCode
|
|
218
223
|
* @param settingKey
|
|
219
|
-
* @private
|
|
220
224
|
*/
|
|
221
|
-
|
|
225
|
+
public async getParsedCrudStdAppForSettingKey(stdAction: ICrudStdActionParams): Promise<ICrudStdAppInfoForSettingKey> {
|
|
222
226
|
const { appCode, settingKey, buttonSettingKey } = stdAction || {};
|
|
223
227
|
if (!appCode) {
|
|
224
228
|
throw new BizException('缺少参数:curdStdAppCode');
|
|
@@ -34,7 +34,7 @@ function fixCfgModel(cfgModel: IRequestCfgModel2) {
|
|
|
34
34
|
return enableStandardUpdateCfg;
|
|
35
35
|
}
|
|
36
36
|
// update 、insert 添加 by
|
|
37
|
-
return ['by']; // 创建/修改语句默认添加by
|
|
37
|
+
return ['by', 'at']; // 创建/修改语句默认添加by
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
const getConditionCfgArray = () => {
|
|
@@ -55,11 +55,13 @@ function fixCfgModel(cfgModel: IRequestCfgModel2) {
|
|
|
55
55
|
'condition.created_by': { contextAsString: CTX_VISITOR_ID },
|
|
56
56
|
'condition.created_account_type': { contextAsString: CTX_VISITOR_ACCOUNT_TYPE },
|
|
57
57
|
|
|
58
|
+
'data.created_at': { functionName: 'getCurrentTimeString' },
|
|
58
59
|
'data.created_by': { contextAsString: CTX_VISITOR_ID },
|
|
59
60
|
'data.created_avatar': { contextAsString: CTX_VISITOR_AVATAR },
|
|
60
61
|
'data.created_nickname': { contextAsString: CTX_VISITOR_NICKNAME },
|
|
61
62
|
'data.created_account_type': { contextAsString: CTX_VISITOR_ACCOUNT_TYPE },
|
|
62
63
|
|
|
64
|
+
'data.modified_at': { functionName: 'getCurrentTimeString' },
|
|
63
65
|
'data.modified_by': { contextAsString: CTX_VISITOR_ID },
|
|
64
66
|
'data.modified_avatar': { contextAsString: CTX_VISITOR_AVATAR },
|
|
65
67
|
'data.modified_nickname': { contextAsString: CTX_VISITOR_NICKNAME },
|