midway-fatcms 0.0.1-beta.24 → 0.0.1-beta.26
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/models/RedisKeys.d.ts +1 -0
- package/dist/models/RedisKeys.js +2 -1
- package/dist/service/EnumInfoService.js +2 -1
- package/dist/service/anyapi/AnyApiSandboxService.js +12 -12
- package/dist/service/asyncTask/AsyncTaskRunnerService.js +3 -3
- package/dist/service/asyncTask/handler/ExportExcelAsyncTaskHandler.js +36 -17
- package/package.json +1 -1
- package/src/models/AsyncTaskModel.ts +82 -82
- package/src/models/RedisKeys.ts +2 -1
- package/src/service/AuthService.ts +272 -275
- package/src/service/EnumInfoService.ts +5 -4
- package/src/service/FileCenterService.ts +4 -4
- package/src/service/anyapi/AnyApiSandboxService.ts +121 -121
- package/src/service/anyapi/AnyApiService.ts +186 -187
- package/src/service/asyncTask/AsyncTaskRunnerService.ts +3 -3
- package/src/service/asyncTask/handler/ExportExcelAsyncTaskHandler.ts +37 -16
package/dist/models/RedisKeys.js
CHANGED
|
@@ -9,6 +9,7 @@ const RedisKeys = {
|
|
|
9
9
|
VISIT_STAT_LOCK_PREFIX: 'FatVsLock_',
|
|
10
10
|
VISIT_STAT_DATE_PREFIX: 'FatVsDate_',
|
|
11
11
|
LINK_TO_CUSTOM_PREFIX: 'FatLinkToCustom@@',
|
|
12
|
-
CURD_MIX_BY_DICT_PREFIX: '
|
|
12
|
+
CURD_MIX_BY_DICT_PREFIX: 'FatCurdMixByDict@@',
|
|
13
|
+
QUERY_ENUM_INFO_PREFIX: 'FatQueryEnum@@',
|
|
13
14
|
};
|
|
14
15
|
exports.RedisKeys = RedisKeys;
|
|
@@ -19,6 +19,7 @@ const parseConfig_1 = require("../libs/utils/parseConfig");
|
|
|
19
19
|
const RedisCacheService_1 = require("./base/RedisCacheService");
|
|
20
20
|
const CurdMixByLinkToCustomService_1 = require("./curd/CurdMixByLinkToCustomService");
|
|
21
21
|
const global_config_1 = require("../libs/global-config/global-config");
|
|
22
|
+
const RedisKeys_1 = require("../models/RedisKeys");
|
|
22
23
|
function filterEmpty(e) {
|
|
23
24
|
return e.label && typeof e.value !== 'undefined';
|
|
24
25
|
}
|
|
@@ -28,7 +29,7 @@ let EnumInfoService = class EnumInfoService {
|
|
|
28
29
|
const result = [];
|
|
29
30
|
for (let i = 0; i < codeList.length; i++) {
|
|
30
31
|
const { code, type } = codeList[i];
|
|
31
|
-
const cacheKey =
|
|
32
|
+
const cacheKey = `${RedisKeys_1.RedisKeys.QUERY_ENUM_INFO_PREFIX}${type}@@${code}`;
|
|
32
33
|
const emums = refreshCache ? null : await this.redisCacheService.getJsonObject(cacheKey);
|
|
33
34
|
if (!Array.isArray(emums) || emums.length === 0) {
|
|
34
35
|
let values;
|
|
@@ -74,18 +74,18 @@ let AnyApiSandboxService = class AnyApiSandboxService extends BaseService_1.Base
|
|
|
74
74
|
};
|
|
75
75
|
const nextLine100 = new Array(10).fill('\n').join('');
|
|
76
76
|
const bindCode = this.toBindCodeString('httpController', newContext, 'sandbox');
|
|
77
|
-
const code = `
|
|
78
|
-
(async () => {
|
|
79
|
-
${nextLine100}${func_code}; // 必须有一个 class HttpController { async handleRequest(params){} }
|
|
80
|
-
${nextLine100}
|
|
81
|
-
try {
|
|
82
|
-
const httpController = new HttpController();
|
|
83
|
-
${bindCode}
|
|
84
|
-
const res = await httpController.handleRequest(sandbox.allParams.params);
|
|
85
|
-
sandbox.returnSuccess(res);
|
|
86
|
-
} catch (e) {
|
|
87
|
-
sandbox.returnError(e)
|
|
88
|
-
}
|
|
77
|
+
const code = `
|
|
78
|
+
(async () => {
|
|
79
|
+
${nextLine100}${func_code}; // 必须有一个 class HttpController { async handleRequest(params){} }
|
|
80
|
+
${nextLine100}
|
|
81
|
+
try {
|
|
82
|
+
const httpController = new HttpController();
|
|
83
|
+
${bindCode}
|
|
84
|
+
const res = await httpController.handleRequest(sandbox.allParams.params);
|
|
85
|
+
sandbox.returnSuccess(res);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
sandbox.returnError(e)
|
|
88
|
+
}
|
|
89
89
|
})(); `;
|
|
90
90
|
try {
|
|
91
91
|
const script = getCompiledScript(anyApi, code);
|
|
@@ -64,7 +64,7 @@ class AsyncTaskRunner {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
catch (error) {
|
|
67
|
-
schedule_1.ANONYMOUS_CONTEXT.getApp().getCoreLogger().error('executeTaskList error', error);
|
|
67
|
+
schedule_1.ANONYMOUS_CONTEXT.getApp().getCoreLogger().error('[AsyncTaskRunner] executeTaskList error', error);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
this.isBusy = false;
|
|
@@ -178,7 +178,7 @@ let AsyncTaskRunnerService = class AsyncTaskRunnerService extends BaseService_1.
|
|
|
178
178
|
});
|
|
179
179
|
// 开始执行。
|
|
180
180
|
exports.ASYNC_TASK_RUNNER.executeTaskList(taskList).then(() => {
|
|
181
|
-
console.log('ASYNC_TASK_RUNNER finished taskIds ==> ' + JSON.stringify(taskIds));
|
|
181
|
+
console.log('[AsyncTaskRunnerService] ASYNC_TASK_RUNNER finished taskIds ==> ' + JSON.stringify(taskIds));
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
async runBySchedule() {
|
|
@@ -201,7 +201,7 @@ let AsyncTaskRunnerService = class AsyncTaskRunnerService extends BaseService_1.
|
|
|
201
201
|
await this.fetchPendingTasks();
|
|
202
202
|
}
|
|
203
203
|
catch (e) {
|
|
204
|
-
console.error('fetchPendingTasks error', (0, errorToString_1.errorToString)(e));
|
|
204
|
+
console.error('[AsyncTaskRunnerService] fetchPendingTasks error', (0, errorToString_1.errorToString)(e));
|
|
205
205
|
}
|
|
206
206
|
await this.redisService.del(ASYNC_TASK_LOCK);
|
|
207
207
|
return Promise.resolve();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ExportExcelAsyncTaskHandler = void 0;
|
|
4
|
-
const schedule_1 = require("../../../schedule");
|
|
5
4
|
const AsyncTaskModel_1 = require("../../../models/AsyncTaskModel");
|
|
5
|
+
const schedule_1 = require("../../../schedule");
|
|
6
|
+
const AsyncTaskModel_2 = require("../../../models/AsyncTaskModel");
|
|
6
7
|
const ExportExcelByStdCrudHandler_1 = require("./ExportExcelByStdCrudHandler");
|
|
7
8
|
const ExportExcelByInnerHttpHandler_1 = require("./ExportExcelByInnerHttpHandler");
|
|
8
9
|
const bizmodels_1 = require("../../../models/bizmodels");
|
|
@@ -13,6 +14,7 @@ const fs2 = require("node:fs/promises");
|
|
|
13
14
|
const path = require("node:path");
|
|
14
15
|
const functions_1 = require("../../../libs/utils/functions");
|
|
15
16
|
const userSession_1 = require("../../../models/userSession");
|
|
17
|
+
const errorToString_1 = require("../../../libs/utils/errorToString");
|
|
16
18
|
const indexRef = { current: 0 };
|
|
17
19
|
async function createFileFolder(distFileFolder) {
|
|
18
20
|
try {
|
|
@@ -31,7 +33,7 @@ function getExcelAsyncTaskHandler(asyncTaskContext, ctx) {
|
|
|
31
33
|
if (inputParams && inputParams.appType === bizmodels_1.StdCrudExportInputParamsAppType.INNER_HTTP) {
|
|
32
34
|
return new ExportExcelByInnerHttpHandler_1.ExportExcelByInnerHttpHandler(asyncTaskContext, inputParams, ctx);
|
|
33
35
|
}
|
|
34
|
-
throw new Error('[getExcelAsyncTaskHandler]appType
|
|
36
|
+
throw new Error('[getExcelAsyncTaskHandler]appType不支持;appType = ' + inputParams.appType);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* 多实例,每个任务一个实例。
|
|
@@ -53,7 +55,9 @@ class ExportExcelAsyncTask {
|
|
|
53
55
|
return fatcmsExportExcelTmpFilePath;
|
|
54
56
|
}
|
|
55
57
|
async executeWithContext() {
|
|
56
|
-
this.
|
|
58
|
+
const taskElement = this.asyncTaskContext.task;
|
|
59
|
+
const taskId = _.get(this.asyncTaskContext, 'task.id');
|
|
60
|
+
this.ctx.logger.info('[ExportExcelAsyncTask] executeWithContext start, taskId=' + taskId);
|
|
57
61
|
const pageSize = await this.excelAsyncTaskHandler.getPageSize();
|
|
58
62
|
const fileName = await this.getExcelFileName(); // 文件名
|
|
59
63
|
const distFileFolder = this.getDistFileFolder();
|
|
@@ -62,7 +66,7 @@ class ExportExcelAsyncTask {
|
|
|
62
66
|
const totalCount = await this.getTotalCount();
|
|
63
67
|
await this.asyncTaskContext.updateTaskStatus({
|
|
64
68
|
output_total_records: totalCount,
|
|
65
|
-
output_file_format:
|
|
69
|
+
output_file_format: AsyncTaskModel_2.SysAsyncFileFormat.CSV,
|
|
66
70
|
output_file_path: diskFilePath,
|
|
67
71
|
});
|
|
68
72
|
this.headerColumns = await this.getExcelHeader();
|
|
@@ -74,28 +78,42 @@ class ExportExcelAsyncTask {
|
|
|
74
78
|
csvStream.write('\ufeff'); // 写入BOM头,解决中文乱码问题
|
|
75
79
|
csvStream.write(this.formatToCsvHeader(this.headerColumns));
|
|
76
80
|
let processed_records = 0;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
try {
|
|
82
|
+
if (typeof totalCount === 'number' && totalCount > 0) {
|
|
83
|
+
const batchCount = Math.ceil(totalCount / pageSize);
|
|
84
|
+
for (let i = 0; i < batchCount; i++) {
|
|
85
|
+
const num = await this.writeExcelBatchData(csvStream, i + 1, pageSize);
|
|
86
|
+
processed_records = processed_records + num;
|
|
87
|
+
const progress = Math.round((processed_records / totalCount) * 100);
|
|
88
|
+
await this.asyncTaskContext.updateTaskStatus({
|
|
89
|
+
processed_records,
|
|
90
|
+
progress,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
87
93
|
}
|
|
94
|
+
taskElement.task_status = AsyncTaskModel_1.SysAsyncTaskStatus.SUCCEEDED;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
taskElement.task_status = AsyncTaskModel_1.SysAsyncTaskStatus.FAILED;
|
|
98
|
+
taskElement.error_message = (0, errorToString_1.errorToString)(error);
|
|
99
|
+
const progress = Math.round((processed_records / totalCount) * 100);
|
|
100
|
+
await this.asyncTaskContext.updateTaskStatus({
|
|
101
|
+
processed_records,
|
|
102
|
+
progress,
|
|
103
|
+
task_status: taskElement.task_status,
|
|
104
|
+
error_message: taskElement.error_message,
|
|
105
|
+
});
|
|
88
106
|
}
|
|
89
107
|
csvStream.end();
|
|
90
108
|
ws.on('finish', async () => {
|
|
91
|
-
this.ctx.logger.info('[ExportExcelAsyncTask] executeWithContext finish');
|
|
109
|
+
this.ctx.logger.info('[ExportExcelAsyncTask] executeWithContext finish, taskId=' + taskId);
|
|
92
110
|
const fsStat = await fs2.stat(diskFilePath);
|
|
93
111
|
const output_file_size = fsStat.size;
|
|
94
112
|
this.asyncTaskContext.updateTaskStatus({
|
|
95
113
|
output_file_size,
|
|
96
114
|
});
|
|
97
115
|
});
|
|
98
|
-
this.ctx.logger.info('[ExportExcelAsyncTask] executeWithContext end');
|
|
116
|
+
this.ctx.logger.info('[ExportExcelAsyncTask] executeWithContext end, taskId=' + taskId);
|
|
99
117
|
}
|
|
100
118
|
formatToCsvHeader(headerColumns) {
|
|
101
119
|
return headerColumns.map(item => {
|
|
@@ -180,7 +198,8 @@ class ExportExcelAsyncTask {
|
|
|
180
198
|
*/
|
|
181
199
|
class ExportExcelAsyncTaskHandler {
|
|
182
200
|
async execute(asyncTaskContext) {
|
|
183
|
-
|
|
201
|
+
const taskId = _.get(asyncTaskContext, 'task.id');
|
|
202
|
+
console.log('[ExportExcelAsyncTaskHandler] execute, taskId=>' + taskId);
|
|
184
203
|
const res = await schedule_1.ANONYMOUS_CONTEXT.runServiceAtAnonymousContext(async (ctx) => {
|
|
185
204
|
var _a;
|
|
186
205
|
const createdUserSession = (0, functions_1.parseJsonObject)((_a = asyncTaskContext === null || asyncTaskContext === void 0 ? void 0 : asyncTaskContext.task) === null || _a === void 0 ? void 0 : _a.created_user_session);
|
package/package.json
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
export interface SysAsyncTaskEntity {
|
|
2
|
-
id: number;
|
|
3
|
-
task_uuid: string;
|
|
4
|
-
task_name: string;
|
|
5
|
-
task_description: string | null;
|
|
6
|
-
task_type: string;
|
|
7
|
-
task_status: SysAsyncTaskStatus;
|
|
8
|
-
input_params: any;
|
|
9
|
-
output_result: any | null;
|
|
10
|
-
|
|
11
|
-
input_file_path: string | null;
|
|
12
|
-
input_file_format: SysAsyncFileFormat | null;
|
|
13
|
-
input_file_size: number | null;
|
|
14
|
-
|
|
15
|
-
output_file_path: string | null;
|
|
16
|
-
output_file_format: SysAsyncFileFormat | null;
|
|
17
|
-
output_file_size: number | null;
|
|
18
|
-
|
|
19
|
-
input_total_records: number | null;
|
|
20
|
-
output_total_records: number | null;
|
|
21
|
-
processed_records: number;
|
|
22
|
-
progress: number;
|
|
23
|
-
error_message: string | null;
|
|
24
|
-
error_records: any | null;
|
|
25
|
-
created_by: string | null;
|
|
26
|
-
priority: number;
|
|
27
|
-
retry_count: number;
|
|
28
|
-
max_retries: number;
|
|
29
|
-
|
|
30
|
-
parent_task_id: number | null;
|
|
31
|
-
created_at: Date | string | null;
|
|
32
|
-
started_at: Date | string | null;
|
|
33
|
-
updated_at: Date | string | null;
|
|
34
|
-
expired_at: Date | string | null;
|
|
35
|
-
completed_at: Date | string | null;
|
|
36
|
-
created_user_session: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type SysAsyncTaskPartial = Partial<SysAsyncTaskEntity>;
|
|
40
|
-
|
|
41
|
-
export enum SysAsyncTaskStatus {
|
|
42
|
-
PENDING = 'PENDING', // 等待中,还未进入排队
|
|
43
|
-
RUNNING = 'RUNNING', // 运行中
|
|
44
|
-
SUCCEEDED = 'SUCCEEDED', // 终止状态:全部成功
|
|
45
|
-
PART_SUCCEEDED = 'PART_SUCCEEDED'
|
|
46
|
-
FAILED = 'FAILED', // 终止状态:失败
|
|
47
|
-
CANCELLED = 'CANCELLED', // 取消
|
|
48
|
-
PAUSED = 'PAUSED', // 暂停
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 导出的文件名后缀
|
|
53
|
-
*/
|
|
54
|
-
export enum SysAsyncFileFormat {
|
|
55
|
-
XLSX = 'xlsx',
|
|
56
|
-
CSV = 'csv',
|
|
57
|
-
JSON = 'json',
|
|
58
|
-
PDF = 'pdf',
|
|
59
|
-
TXT = 'txt',
|
|
60
|
-
XML = 'xml',
|
|
61
|
-
ZIP = 'zip',
|
|
62
|
-
HTML = 'html',
|
|
63
|
-
PNG = 'png',
|
|
64
|
-
JPG = 'jpg',
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface ISysAsyncTaskHandler {
|
|
68
|
-
execute(asyncTaskContext: SysAsyncTaskContext): Promise<void>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface SysAsyncTaskContext {
|
|
72
|
-
task: SysAsyncTaskEntity;
|
|
73
|
-
updateTaskStatus: (sysAsyncTaskPartial: SysAsyncTaskPartial) => any;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface SysAsyncTaskHandlerConfig {
|
|
77
|
-
taskType: string;
|
|
78
|
-
handler: ISysAsyncTaskHandler;
|
|
79
|
-
maxRetries?: number;
|
|
80
|
-
priority?: number;
|
|
81
|
-
expireSeconds?: number;
|
|
82
|
-
}
|
|
1
|
+
export interface SysAsyncTaskEntity {
|
|
2
|
+
id: number;
|
|
3
|
+
task_uuid: string;
|
|
4
|
+
task_name: string;
|
|
5
|
+
task_description: string | null;
|
|
6
|
+
task_type: string;
|
|
7
|
+
task_status: SysAsyncTaskStatus;
|
|
8
|
+
input_params: any;
|
|
9
|
+
output_result: any | null;
|
|
10
|
+
|
|
11
|
+
input_file_path: string | null;
|
|
12
|
+
input_file_format: SysAsyncFileFormat | null;
|
|
13
|
+
input_file_size: number | null;
|
|
14
|
+
|
|
15
|
+
output_file_path: string | null;
|
|
16
|
+
output_file_format: SysAsyncFileFormat | null;
|
|
17
|
+
output_file_size: number | null;
|
|
18
|
+
|
|
19
|
+
input_total_records: number | null;
|
|
20
|
+
output_total_records: number | null;
|
|
21
|
+
processed_records: number;
|
|
22
|
+
progress: number;
|
|
23
|
+
error_message: string | null;
|
|
24
|
+
error_records: any | null;
|
|
25
|
+
created_by: string | null;
|
|
26
|
+
priority: number;
|
|
27
|
+
retry_count: number;
|
|
28
|
+
max_retries: number;
|
|
29
|
+
|
|
30
|
+
parent_task_id: number | null;
|
|
31
|
+
created_at: Date | string | null;
|
|
32
|
+
started_at: Date | string | null;
|
|
33
|
+
updated_at: Date | string | null;
|
|
34
|
+
expired_at: Date | string | null;
|
|
35
|
+
completed_at: Date | string | null;
|
|
36
|
+
created_user_session: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type SysAsyncTaskPartial = Partial<SysAsyncTaskEntity>;
|
|
40
|
+
|
|
41
|
+
export enum SysAsyncTaskStatus {
|
|
42
|
+
PENDING = 'PENDING', // 等待中,还未进入排队
|
|
43
|
+
RUNNING = 'RUNNING', // 运行中
|
|
44
|
+
SUCCEEDED = 'SUCCEEDED', // 终止状态:全部成功
|
|
45
|
+
PART_SUCCEEDED = 'PART_SUCCEEDED', // 终止状态:部分成功
|
|
46
|
+
FAILED = 'FAILED', // 终止状态:失败
|
|
47
|
+
CANCELLED = 'CANCELLED', // 取消
|
|
48
|
+
PAUSED = 'PAUSED', // 暂停
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 导出的文件名后缀
|
|
53
|
+
*/
|
|
54
|
+
export enum SysAsyncFileFormat {
|
|
55
|
+
XLSX = 'xlsx',
|
|
56
|
+
CSV = 'csv',
|
|
57
|
+
JSON = 'json',
|
|
58
|
+
PDF = 'pdf',
|
|
59
|
+
TXT = 'txt',
|
|
60
|
+
XML = 'xml',
|
|
61
|
+
ZIP = 'zip',
|
|
62
|
+
HTML = 'html',
|
|
63
|
+
PNG = 'png',
|
|
64
|
+
JPG = 'jpg',
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface ISysAsyncTaskHandler {
|
|
68
|
+
execute(asyncTaskContext: SysAsyncTaskContext): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface SysAsyncTaskContext {
|
|
72
|
+
task: SysAsyncTaskEntity;
|
|
73
|
+
updateTaskStatus: (sysAsyncTaskPartial: SysAsyncTaskPartial) => any;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SysAsyncTaskHandlerConfig {
|
|
77
|
+
taskType: string;
|
|
78
|
+
handler: ISysAsyncTaskHandler;
|
|
79
|
+
maxRetries?: number;
|
|
80
|
+
priority?: number;
|
|
81
|
+
expireSeconds?: number;
|
|
82
|
+
}
|
package/src/models/RedisKeys.ts
CHANGED
|
@@ -6,7 +6,8 @@ const RedisKeys = {
|
|
|
6
6
|
VISIT_STAT_LOCK_PREFIX: 'FatVsLock_',
|
|
7
7
|
VISIT_STAT_DATE_PREFIX: 'FatVsDate_',
|
|
8
8
|
LINK_TO_CUSTOM_PREFIX: 'FatLinkToCustom@@',
|
|
9
|
-
CURD_MIX_BY_DICT_PREFIX: '
|
|
9
|
+
CURD_MIX_BY_DICT_PREFIX: 'FatCurdMixByDict@@',
|
|
10
|
+
QUERY_ENUM_INFO_PREFIX: 'FatQueryEnum@@',
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export { RedisKeys };
|