@agile-team/mach-report 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1663 -0
- package/dist/index.d.cts +344 -0
- package/dist/index.d.ts +344 -13
- package/dist/index.js +1611 -14
- package/dist/manager.cjs +122 -0
- package/dist/{manager/api.d.ts → manager.d.cts} +55 -3
- package/dist/manager.d.ts +97 -5
- package/dist/manager.js +119 -6
- package/dist/pdf.cjs +52530 -0
- package/dist/pdf.d.cts +33 -0
- package/dist/pdf.d.ts +31 -4
- package/dist/pdf.js +52527 -7
- package/dist/sql.cjs +45207 -0
- package/dist/sql.d.cts +95 -0
- package/dist/sql.d.ts +93 -3
- package/dist/sql.js +45194 -6
- package/dist/textwrap-DWzM7pt1.d.cts +135 -0
- package/dist/textwrap-DWzM7pt1.d.ts +135 -0
- package/package.json +44 -15
- package/dist/builder/template-builder.d.ts +0 -53
- package/dist/builder/template-builder.js +0 -153
- package/dist/builder/template-builder.js.map +0 -1
- package/dist/compat/jh4j-template.d.ts +0 -12
- package/dist/compat/jh4j-template.js +0 -196
- package/dist/compat/jh4j-template.js.map +0 -1
- package/dist/defaults.d.ts +0 -27
- package/dist/defaults.js +0 -28
- package/dist/defaults.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/layout/paginate.d.ts +0 -51
- package/dist/layout/paginate.js +0 -197
- package/dist/layout/paginate.js.map +0 -1
- package/dist/layout/textwrap.d.ts +0 -36
- package/dist/layout/textwrap.js +0 -173
- package/dist/layout/textwrap.js.map +0 -1
- package/dist/manager/api.js +0 -101
- package/dist/manager/api.js.map +0 -1
- package/dist/manager/index.d.ts +0 -2
- package/dist/manager/index.js +0 -3
- package/dist/manager/index.js.map +0 -1
- package/dist/manager/types.d.ts +0 -50
- package/dist/manager/types.js +0 -8
- package/dist/manager/types.js.map +0 -1
- package/dist/manager.js.map +0 -1
- package/dist/pdf/font-loader.d.ts +0 -5
- package/dist/pdf/font-loader.js +0 -84
- package/dist/pdf/font-loader.js.map +0 -1
- package/dist/pdf/index.d.ts +0 -2
- package/dist/pdf/index.js +0 -3
- package/dist/pdf/index.js.map +0 -1
- package/dist/pdf/render-pdf.d.ts +0 -19
- package/dist/pdf/render-pdf.js +0 -284
- package/dist/pdf/render-pdf.js.map +0 -1
- package/dist/pdf.js.map +0 -1
- package/dist/render/canvas.d.ts +0 -61
- package/dist/render/canvas.js +0 -402
- package/dist/render/canvas.js.map +0 -1
- package/dist/render/dom.d.ts +0 -10
- package/dist/render/dom.js +0 -311
- package/dist/render/dom.js.map +0 -1
- package/dist/render/grid-geometry.d.ts +0 -41
- package/dist/render/grid-geometry.js +0 -131
- package/dist/render/grid-geometry.js.map +0 -1
- package/dist/render/style.d.ts +0 -40
- package/dist/render/style.js +0 -39
- package/dist/render/style.js.map +0 -1
- package/dist/render/window.d.ts +0 -23
- package/dist/render/window.js +0 -58
- package/dist/render/window.js.map +0 -1
- package/dist/schema/render-plan.d.ts +0 -96
- package/dist/schema/render-plan.js +0 -25
- package/dist/schema/render-plan.js.map +0 -1
- package/dist/schema/validate.d.ts +0 -15
- package/dist/schema/validate.js +0 -129
- package/dist/schema/validate.js.map +0 -1
- package/dist/sql/ast-check.d.ts +0 -14
- package/dist/sql/ast-check.js +0 -44
- package/dist/sql/ast-check.js.map +0 -1
- package/dist/sql/compile.d.ts +0 -31
- package/dist/sql/compile.js +0 -145
- package/dist/sql/compile.js.map +0 -1
- package/dist/sql/expr.d.ts +0 -21
- package/dist/sql/expr.js +0 -123
- package/dist/sql/expr.js.map +0 -1
- package/dist/sql/index.d.ts +0 -4
- package/dist/sql/index.js +0 -5
- package/dist/sql/index.js.map +0 -1
- package/dist/sql/tokenizer.d.ts +0 -25
- package/dist/sql/tokenizer.js +0 -124
- package/dist/sql/tokenizer.js.map +0 -1
- package/dist/sql.js.map +0 -1
- package/dist/units.d.ts +0 -11
- package/dist/units.js +0 -26
- package/dist/units.js.map +0 -1
package/dist/manager.cjs
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/manager/types.ts
|
|
4
|
+
var ReportAdminError = class extends Error {
|
|
5
|
+
constructor(message, url) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.url = url;
|
|
8
|
+
this.name = "ReportAdminError";
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/manager/api.ts
|
|
13
|
+
var BASE = "/report/codePrintReport";
|
|
14
|
+
var LOCK_BASE = "/report/codePrintReportLock";
|
|
15
|
+
function unwrap(response, url) {
|
|
16
|
+
const body = response;
|
|
17
|
+
if (body && body.code != null && body.code !== 200) {
|
|
18
|
+
throw new ReportAdminError(String(body.message || "\u8BF7\u6C42\u5931\u8D25"), url);
|
|
19
|
+
}
|
|
20
|
+
return body?.data ?? body;
|
|
21
|
+
}
|
|
22
|
+
function createReportAdminClient(options) {
|
|
23
|
+
const { request } = options;
|
|
24
|
+
const base = options.baseUrl ?? "";
|
|
25
|
+
return {
|
|
26
|
+
/** 模板列表(分页) */
|
|
27
|
+
async listReports(query = {}) {
|
|
28
|
+
const url = `${base}${BASE}/list`;
|
|
29
|
+
return unwrap(
|
|
30
|
+
await request({ url, method: "get", params: { current: 1, size: 20, ...query } }),
|
|
31
|
+
url
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
/** 模板详情(content 为 jh4j 私有模板 JSON 字符串,可喂给 importJh4jTemplateContent) */
|
|
35
|
+
async getReport(id) {
|
|
36
|
+
const url = `${base}${BASE}/getById`;
|
|
37
|
+
return unwrap(await request({ url, method: "get", params: { id } }), url);
|
|
38
|
+
},
|
|
39
|
+
/** 保存模板(jh4j:PUT,body {id, code, name, content}) */
|
|
40
|
+
async updateReport(input) {
|
|
41
|
+
const url = `${base}${BASE}/update`;
|
|
42
|
+
return unwrap(await request({ url, method: "put", data: input }), url);
|
|
43
|
+
},
|
|
44
|
+
/** 导出模板定义包(body = ID 数组,返回 ZIP blob) */
|
|
45
|
+
async exportDefinition(ids) {
|
|
46
|
+
const url = `${base}${BASE}/exportDefinition`;
|
|
47
|
+
return request({ url, method: "post", data: ids });
|
|
48
|
+
},
|
|
49
|
+
/** 导入模板定义包(multipart: file + strategy) */
|
|
50
|
+
async importDefinition(file, strategy) {
|
|
51
|
+
const url = `${base}${BASE}/importDefinition`;
|
|
52
|
+
const form = new FormData();
|
|
53
|
+
form.append("file", file);
|
|
54
|
+
form.append("strategy", strategy);
|
|
55
|
+
return request({ url, method: "post", data: form });
|
|
56
|
+
},
|
|
57
|
+
/** 数据集列表 */
|
|
58
|
+
async listDatasets(reportId) {
|
|
59
|
+
const url = `${base}${BASE}Ds/list`;
|
|
60
|
+
return unwrap(
|
|
61
|
+
await request({ url, method: "get", params: { reportId, current: 1, size: 999 } }),
|
|
62
|
+
url
|
|
63
|
+
);
|
|
64
|
+
},
|
|
65
|
+
/** 参数列表 */
|
|
66
|
+
async listParams(reportId) {
|
|
67
|
+
const url = `${base}${BASE}Param/list`;
|
|
68
|
+
return unwrap(
|
|
69
|
+
await request({ url, method: "get", params: { reportId, current: 1, size: 999 } }),
|
|
70
|
+
url
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
/** 模板锁:进入设计器前获取(40s 心跳由 holdLock 驱动) */
|
|
74
|
+
async acquireLock(reportId) {
|
|
75
|
+
const url = `${base}${LOCK_BASE}/acquire`;
|
|
76
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
77
|
+
},
|
|
78
|
+
async lockHeartbeat(reportId) {
|
|
79
|
+
const url = `${base}${LOCK_BASE}/heartbeat`;
|
|
80
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
81
|
+
},
|
|
82
|
+
async releaseLock(reportId) {
|
|
83
|
+
const url = `${base}${LOCK_BASE}/release`;
|
|
84
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* 持锁执行:acquire → fn(期间自动心跳)→ release(finally)。
|
|
88
|
+
* 返回 fn 的结果;获取锁失败时抛 ReportAdminError。
|
|
89
|
+
* 心跳连续失败(默认 2 次)视为锁丢失:触发 onLockLost 回调并停止心跳,
|
|
90
|
+
* fn 继续执行(避免中途丢弃用户编辑),由调用方决定是否提示/中止。
|
|
91
|
+
*/
|
|
92
|
+
async holdLock(reportId, fn, options2 = {}) {
|
|
93
|
+
await this.acquireLock(reportId);
|
|
94
|
+
const failLimit = Math.max(1, options2.heartbeatFailLimit ?? 2);
|
|
95
|
+
let consecutiveFailures = 0;
|
|
96
|
+
let lockLost = false;
|
|
97
|
+
const timer = setInterval(() => {
|
|
98
|
+
void this.lockHeartbeat(reportId).then(() => {
|
|
99
|
+
consecutiveFailures = 0;
|
|
100
|
+
}).catch((e) => {
|
|
101
|
+
consecutiveFailures++;
|
|
102
|
+
if (!lockLost && consecutiveFailures >= failLimit) {
|
|
103
|
+
lockLost = true;
|
|
104
|
+
options2.onLockLost?.(
|
|
105
|
+
`\u6A21\u677F\u9501\u5FC3\u8DF3\u8FDE\u7EED ${consecutiveFailures} \u6B21\u5931\u8D25\uFF08${e instanceof Error ? e.message : String(e)}\uFF09\uFF0C\u9501\u53EF\u80FD\u5DF2\u88AB\u91CA\u653E`
|
|
106
|
+
);
|
|
107
|
+
clearInterval(timer);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}, 4e4);
|
|
111
|
+
try {
|
|
112
|
+
return await fn();
|
|
113
|
+
} finally {
|
|
114
|
+
clearInterval(timer);
|
|
115
|
+
await this.releaseLock(reportId).catch(() => void 0);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.ReportAdminError = ReportAdminError;
|
|
122
|
+
exports.createReportAdminClient = createReportAdminClient;
|
|
@@ -1,5 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface ReportRecord {
|
|
2
|
+
id: string;
|
|
3
|
+
code?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
publishStatus?: string;
|
|
6
|
+
directoryId?: string;
|
|
7
|
+
updateTime?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
interface PageResult<T> {
|
|
11
|
+
records: T[];
|
|
12
|
+
total?: number;
|
|
13
|
+
current?: number;
|
|
14
|
+
size?: number;
|
|
15
|
+
}
|
|
16
|
+
interface DatasetRecord {
|
|
17
|
+
id?: string;
|
|
18
|
+
reportId?: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
datasourceCode?: string;
|
|
23
|
+
sqlText?: string;
|
|
24
|
+
apiUrl?: string;
|
|
25
|
+
fields?: unknown[];
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
interface ParamRecord {
|
|
29
|
+
id?: string;
|
|
30
|
+
reportId?: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
defaultValue?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
type ImportStrategy = "overwrite" | "skip";
|
|
36
|
+
type RequestFn = (config: {
|
|
37
|
+
url: string;
|
|
38
|
+
method: string;
|
|
39
|
+
params?: Record<string, unknown>;
|
|
40
|
+
data?: unknown;
|
|
41
|
+
}) => Promise<unknown>;
|
|
42
|
+
interface ApiResponse<T = unknown> {
|
|
43
|
+
code?: number;
|
|
44
|
+
message?: string;
|
|
45
|
+
data?: T;
|
|
46
|
+
}
|
|
47
|
+
declare class ReportAdminError extends Error {
|
|
48
|
+
readonly url: string;
|
|
49
|
+
constructor(message: string, url: string);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare function createReportAdminClient(options: {
|
|
3
53
|
request: RequestFn;
|
|
4
54
|
baseUrl?: string;
|
|
5
55
|
}): {
|
|
@@ -42,4 +92,6 @@ export declare function createReportAdminClient(options: {
|
|
|
42
92
|
heartbeatFailLimit?: number;
|
|
43
93
|
}): Promise<T>;
|
|
44
94
|
};
|
|
45
|
-
|
|
95
|
+
type ReportAdminClient = ReturnType<typeof createReportAdminClient>;
|
|
96
|
+
|
|
97
|
+
export { type ApiResponse, type DatasetRecord, type ImportStrategy, type PageResult, type ParamRecord, type ReportAdminClient, ReportAdminError, type ReportRecord, type RequestFn, createReportAdminClient };
|
package/dist/manager.d.ts
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
interface ReportRecord {
|
|
2
|
+
id: string;
|
|
3
|
+
code?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
publishStatus?: string;
|
|
6
|
+
directoryId?: string;
|
|
7
|
+
updateTime?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
interface PageResult<T> {
|
|
11
|
+
records: T[];
|
|
12
|
+
total?: number;
|
|
13
|
+
current?: number;
|
|
14
|
+
size?: number;
|
|
15
|
+
}
|
|
16
|
+
interface DatasetRecord {
|
|
17
|
+
id?: string;
|
|
18
|
+
reportId?: string;
|
|
19
|
+
code?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
datasourceCode?: string;
|
|
23
|
+
sqlText?: string;
|
|
24
|
+
apiUrl?: string;
|
|
25
|
+
fields?: unknown[];
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
interface ParamRecord {
|
|
29
|
+
id?: string;
|
|
30
|
+
reportId?: string;
|
|
31
|
+
name?: string;
|
|
32
|
+
defaultValue?: string;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
type ImportStrategy = "overwrite" | "skip";
|
|
36
|
+
type RequestFn = (config: {
|
|
37
|
+
url: string;
|
|
38
|
+
method: string;
|
|
39
|
+
params?: Record<string, unknown>;
|
|
40
|
+
data?: unknown;
|
|
41
|
+
}) => Promise<unknown>;
|
|
42
|
+
interface ApiResponse<T = unknown> {
|
|
43
|
+
code?: number;
|
|
44
|
+
message?: string;
|
|
45
|
+
data?: T;
|
|
46
|
+
}
|
|
47
|
+
declare class ReportAdminError extends Error {
|
|
48
|
+
readonly url: string;
|
|
49
|
+
constructor(message: string, url: string);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare function createReportAdminClient(options: {
|
|
53
|
+
request: RequestFn;
|
|
54
|
+
baseUrl?: string;
|
|
55
|
+
}): {
|
|
56
|
+
/** 模板列表(分页) */
|
|
57
|
+
listReports(query?: {
|
|
58
|
+
current?: number;
|
|
59
|
+
size?: number;
|
|
60
|
+
directoryId?: string;
|
|
61
|
+
keyword?: string;
|
|
62
|
+
}): Promise<PageResult<ReportRecord>>;
|
|
63
|
+
/** 模板详情(content 为 jh4j 私有模板 JSON 字符串,可喂给 importJh4jTemplateContent) */
|
|
64
|
+
getReport(id: string): Promise<ReportRecord>;
|
|
65
|
+
/** 保存模板(jh4j:PUT,body {id, code, name, content}) */
|
|
66
|
+
updateReport(input: {
|
|
67
|
+
id: string;
|
|
68
|
+
code?: string;
|
|
69
|
+
name?: string;
|
|
70
|
+
content: string;
|
|
71
|
+
}): Promise<unknown>;
|
|
72
|
+
/** 导出模板定义包(body = ID 数组,返回 ZIP blob) */
|
|
73
|
+
exportDefinition(ids: string[]): Promise<unknown>;
|
|
74
|
+
/** 导入模板定义包(multipart: file + strategy) */
|
|
75
|
+
importDefinition(file: File | Blob, strategy: ImportStrategy): Promise<unknown>;
|
|
76
|
+
/** 数据集列表 */
|
|
77
|
+
listDatasets(reportId: string): Promise<PageResult<DatasetRecord>>;
|
|
78
|
+
/** 参数列表 */
|
|
79
|
+
listParams(reportId: string): Promise<PageResult<ParamRecord>>;
|
|
80
|
+
/** 模板锁:进入设计器前获取(40s 心跳由 holdLock 驱动) */
|
|
81
|
+
acquireLock(reportId: string): Promise<unknown>;
|
|
82
|
+
lockHeartbeat(reportId: string): Promise<unknown>;
|
|
83
|
+
releaseLock(reportId: string): Promise<unknown>;
|
|
84
|
+
/**
|
|
85
|
+
* 持锁执行:acquire → fn(期间自动心跳)→ release(finally)。
|
|
86
|
+
* 返回 fn 的结果;获取锁失败时抛 ReportAdminError。
|
|
87
|
+
* 心跳连续失败(默认 2 次)视为锁丢失:触发 onLockLost 回调并停止心跳,
|
|
88
|
+
* fn 继续执行(避免中途丢弃用户编辑),由调用方决定是否提示/中止。
|
|
89
|
+
*/
|
|
90
|
+
holdLock<T>(reportId: string, fn: () => Promise<T>, options?: {
|
|
91
|
+
onLockLost?: (reason: string) => void;
|
|
92
|
+
heartbeatFailLimit?: number;
|
|
93
|
+
}): Promise<T>;
|
|
94
|
+
};
|
|
95
|
+
type ReportAdminClient = ReturnType<typeof createReportAdminClient>;
|
|
96
|
+
|
|
97
|
+
export { type ApiResponse, type DatasetRecord, type ImportStrategy, type PageResult, type ParamRecord, type ReportAdminClient, ReportAdminError, type ReportRecord, type RequestFn, createReportAdminClient };
|
package/dist/manager.js
CHANGED
|
@@ -1,6 +1,119 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// src/manager/types.ts
|
|
2
|
+
var ReportAdminError = class extends Error {
|
|
3
|
+
constructor(message, url) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.url = url;
|
|
6
|
+
this.name = "ReportAdminError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/manager/api.ts
|
|
11
|
+
var BASE = "/report/codePrintReport";
|
|
12
|
+
var LOCK_BASE = "/report/codePrintReportLock";
|
|
13
|
+
function unwrap(response, url) {
|
|
14
|
+
const body = response;
|
|
15
|
+
if (body && body.code != null && body.code !== 200) {
|
|
16
|
+
throw new ReportAdminError(String(body.message || "\u8BF7\u6C42\u5931\u8D25"), url);
|
|
17
|
+
}
|
|
18
|
+
return body?.data ?? body;
|
|
19
|
+
}
|
|
20
|
+
function createReportAdminClient(options) {
|
|
21
|
+
const { request } = options;
|
|
22
|
+
const base = options.baseUrl ?? "";
|
|
23
|
+
return {
|
|
24
|
+
/** 模板列表(分页) */
|
|
25
|
+
async listReports(query = {}) {
|
|
26
|
+
const url = `${base}${BASE}/list`;
|
|
27
|
+
return unwrap(
|
|
28
|
+
await request({ url, method: "get", params: { current: 1, size: 20, ...query } }),
|
|
29
|
+
url
|
|
30
|
+
);
|
|
31
|
+
},
|
|
32
|
+
/** 模板详情(content 为 jh4j 私有模板 JSON 字符串,可喂给 importJh4jTemplateContent) */
|
|
33
|
+
async getReport(id) {
|
|
34
|
+
const url = `${base}${BASE}/getById`;
|
|
35
|
+
return unwrap(await request({ url, method: "get", params: { id } }), url);
|
|
36
|
+
},
|
|
37
|
+
/** 保存模板(jh4j:PUT,body {id, code, name, content}) */
|
|
38
|
+
async updateReport(input) {
|
|
39
|
+
const url = `${base}${BASE}/update`;
|
|
40
|
+
return unwrap(await request({ url, method: "put", data: input }), url);
|
|
41
|
+
},
|
|
42
|
+
/** 导出模板定义包(body = ID 数组,返回 ZIP blob) */
|
|
43
|
+
async exportDefinition(ids) {
|
|
44
|
+
const url = `${base}${BASE}/exportDefinition`;
|
|
45
|
+
return request({ url, method: "post", data: ids });
|
|
46
|
+
},
|
|
47
|
+
/** 导入模板定义包(multipart: file + strategy) */
|
|
48
|
+
async importDefinition(file, strategy) {
|
|
49
|
+
const url = `${base}${BASE}/importDefinition`;
|
|
50
|
+
const form = new FormData();
|
|
51
|
+
form.append("file", file);
|
|
52
|
+
form.append("strategy", strategy);
|
|
53
|
+
return request({ url, method: "post", data: form });
|
|
54
|
+
},
|
|
55
|
+
/** 数据集列表 */
|
|
56
|
+
async listDatasets(reportId) {
|
|
57
|
+
const url = `${base}${BASE}Ds/list`;
|
|
58
|
+
return unwrap(
|
|
59
|
+
await request({ url, method: "get", params: { reportId, current: 1, size: 999 } }),
|
|
60
|
+
url
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
/** 参数列表 */
|
|
64
|
+
async listParams(reportId) {
|
|
65
|
+
const url = `${base}${BASE}Param/list`;
|
|
66
|
+
return unwrap(
|
|
67
|
+
await request({ url, method: "get", params: { reportId, current: 1, size: 999 } }),
|
|
68
|
+
url
|
|
69
|
+
);
|
|
70
|
+
},
|
|
71
|
+
/** 模板锁:进入设计器前获取(40s 心跳由 holdLock 驱动) */
|
|
72
|
+
async acquireLock(reportId) {
|
|
73
|
+
const url = `${base}${LOCK_BASE}/acquire`;
|
|
74
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
75
|
+
},
|
|
76
|
+
async lockHeartbeat(reportId) {
|
|
77
|
+
const url = `${base}${LOCK_BASE}/heartbeat`;
|
|
78
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
79
|
+
},
|
|
80
|
+
async releaseLock(reportId) {
|
|
81
|
+
const url = `${base}${LOCK_BASE}/release`;
|
|
82
|
+
return unwrap(await request({ url, method: "post", data: { reportId } }), url);
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* 持锁执行:acquire → fn(期间自动心跳)→ release(finally)。
|
|
86
|
+
* 返回 fn 的结果;获取锁失败时抛 ReportAdminError。
|
|
87
|
+
* 心跳连续失败(默认 2 次)视为锁丢失:触发 onLockLost 回调并停止心跳,
|
|
88
|
+
* fn 继续执行(避免中途丢弃用户编辑),由调用方决定是否提示/中止。
|
|
89
|
+
*/
|
|
90
|
+
async holdLock(reportId, fn, options2 = {}) {
|
|
91
|
+
await this.acquireLock(reportId);
|
|
92
|
+
const failLimit = Math.max(1, options2.heartbeatFailLimit ?? 2);
|
|
93
|
+
let consecutiveFailures = 0;
|
|
94
|
+
let lockLost = false;
|
|
95
|
+
const timer = setInterval(() => {
|
|
96
|
+
void this.lockHeartbeat(reportId).then(() => {
|
|
97
|
+
consecutiveFailures = 0;
|
|
98
|
+
}).catch((e) => {
|
|
99
|
+
consecutiveFailures++;
|
|
100
|
+
if (!lockLost && consecutiveFailures >= failLimit) {
|
|
101
|
+
lockLost = true;
|
|
102
|
+
options2.onLockLost?.(
|
|
103
|
+
`\u6A21\u677F\u9501\u5FC3\u8DF3\u8FDE\u7EED ${consecutiveFailures} \u6B21\u5931\u8D25\uFF08${e instanceof Error ? e.message : String(e)}\uFF09\uFF0C\u9501\u53EF\u80FD\u5DF2\u88AB\u91CA\u653E`
|
|
104
|
+
);
|
|
105
|
+
clearInterval(timer);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}, 4e4);
|
|
109
|
+
try {
|
|
110
|
+
return await fn();
|
|
111
|
+
} finally {
|
|
112
|
+
clearInterval(timer);
|
|
113
|
+
await this.releaseLock(reportId).catch(() => void 0);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { ReportAdminError, createReportAdminClient };
|