@mldong/jeeflow 1.0.0 → 1.2.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/README.md +58 -55
- package/dist/engine.d.ts +3 -0
- package/dist/engine.js +66 -7
- package/dist/facade.d.ts +38 -0
- package/dist/facade.js +582 -0
- package/dist/jdbc/ext.d.ts +29 -0
- package/dist/jdbc/ext.js +258 -0
- package/dist/jdbc/shared.d.ts +7 -0
- package/dist/jdbc/shared.js +80 -3
- package/dist/memory-ext.d.ts +21 -0
- package/dist/memory-ext.js +83 -0
- package/dist/memory.d.ts +5 -0
- package/dist/memory.js +36 -0
- package/dist/model.d.ts +33 -0
- package/dist/spi.d.ts +21 -1
- package/package.json +45 -45
package/dist/jdbc/ext.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// 扩展仓储 JDBC 参考实现(v1.1.0)——流程设计 / 设计历史 / 委托代理
|
|
2
|
+
//
|
|
3
|
+
// 与 shared.ts 同一套 SqlAdapter / 占位符约定;分页为单表简单过滤(filters 字段名 EQ)。
|
|
4
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
5
|
+
import { TsIDGenerator } from './shared.js';
|
|
6
|
+
const txStore = new AsyncLocalStorage();
|
|
7
|
+
export class JdbcProcessExtRepository {
|
|
8
|
+
adapter;
|
|
9
|
+
idGen;
|
|
10
|
+
constructor(adapter, idGen = new TsIDGenerator()) {
|
|
11
|
+
this.adapter = adapter;
|
|
12
|
+
this.idGen = idGen;
|
|
13
|
+
}
|
|
14
|
+
sql(s) {
|
|
15
|
+
if (this.adapter.placeholder === '$n') {
|
|
16
|
+
let i = 0;
|
|
17
|
+
return s.replace(/\?/g, () => `$${++i}`);
|
|
18
|
+
}
|
|
19
|
+
return s;
|
|
20
|
+
}
|
|
21
|
+
async c() {
|
|
22
|
+
return txStore.getStore() ?? (await this.adapter.acquire());
|
|
23
|
+
}
|
|
24
|
+
async done(conn) {
|
|
25
|
+
if (!txStore.getStore())
|
|
26
|
+
await this.adapter.release(conn);
|
|
27
|
+
}
|
|
28
|
+
// ── 流程设计 ─────────────────────────────────────────────────────────────
|
|
29
|
+
static DESIGN_COLS = 'id, name, display_name, type, icon, is_deployed, remark, create_time, create_user, update_time, update_user';
|
|
30
|
+
async findDesignById(id) {
|
|
31
|
+
const conn = await this.c();
|
|
32
|
+
try {
|
|
33
|
+
const row = await conn.fetchOne(this.sql(`SELECT ${JdbcProcessExtRepository.DESIGN_COLS} FROM wf_process_design WHERE id = ?`), [id]);
|
|
34
|
+
return row ? this.mapDesign(row) : null;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await this.done(conn);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async saveDesign(d) {
|
|
41
|
+
if (!d.id)
|
|
42
|
+
d.id = this.idGen.nextId();
|
|
43
|
+
const now = new Date();
|
|
44
|
+
if (!d.createTime)
|
|
45
|
+
d.createTime = now;
|
|
46
|
+
if (!d.updateTime)
|
|
47
|
+
d.updateTime = now;
|
|
48
|
+
const conn = await this.c();
|
|
49
|
+
try {
|
|
50
|
+
await conn.execute(this.sql('INSERT INTO wf_process_design (id, name, display_name, type, icon, is_deployed, remark, ' +
|
|
51
|
+
'create_time, create_user, update_time, update_user) VALUES (?,?,?,?,?,?,?,?,?,?,?)'), [d.id, d.name, d.displayName, d.type, d.icon ?? null, d.isDeployed, d.remark ?? null,
|
|
52
|
+
d.createTime, d.createUser, d.updateTime, d.updateUser]);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
await this.done(conn);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async updateDesign(d) {
|
|
59
|
+
const conn = await this.c();
|
|
60
|
+
try {
|
|
61
|
+
await conn.execute(this.sql('UPDATE wf_process_design SET name=?, display_name=?, type=?, icon=?, is_deployed=?, ' +
|
|
62
|
+
'remark=?, update_time=?, update_user=? WHERE id=?'), [d.name, d.displayName, d.type, d.icon ?? null, d.isDeployed, d.remark ?? null,
|
|
63
|
+
new Date(), d.updateUser, d.id]);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await this.done(conn);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async removeDesign(id) {
|
|
70
|
+
const conn = await this.c();
|
|
71
|
+
try {
|
|
72
|
+
await conn.execute(this.sql('DELETE FROM wf_process_design WHERE id=?'), [id]);
|
|
73
|
+
await conn.execute(this.sql('DELETE FROM wf_process_design_his WHERE process_design_id=?'), [id]);
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await this.done(conn);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async pageDesigns(pageNum = 1, pageSize = 10, filters) {
|
|
80
|
+
let sql = `SELECT ${JdbcProcessExtRepository.DESIGN_COLS} FROM wf_process_design t WHERE 1=1`;
|
|
81
|
+
let countSql = 'SELECT COUNT(*) FROM wf_process_design t WHERE 1=1';
|
|
82
|
+
const args = [];
|
|
83
|
+
const args2 = [];
|
|
84
|
+
for (const [col, val] of Object.entries(filters ?? {})) {
|
|
85
|
+
if (['name', 'display_name', 'type'].includes(col)) {
|
|
86
|
+
sql += ` AND t.${col} = ?`;
|
|
87
|
+
countSql += ` AND t.${col} = ?`;
|
|
88
|
+
args.push(val);
|
|
89
|
+
args2.push(val);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const conn = await this.c();
|
|
93
|
+
try {
|
|
94
|
+
const countRow = await conn.fetchOne(this.sql(countSql), args2);
|
|
95
|
+
const total = countRow ? Number(Object.values(countRow)[0]) : 0;
|
|
96
|
+
sql += ' ORDER BY t.id DESC LIMIT ? OFFSET ?';
|
|
97
|
+
args.push(pageSize, (pageNum - 1) * pageSize);
|
|
98
|
+
const rows = await conn.fetchAll(this.sql(sql), args);
|
|
99
|
+
return [rows.map(r => this.mapDesign(r)), total];
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
await this.done(conn);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ── 设计历史 ─────────────────────────────────────────────────────────────
|
|
106
|
+
async saveDesignHis(his) {
|
|
107
|
+
if (!his.id)
|
|
108
|
+
his.id = this.idGen.nextId();
|
|
109
|
+
if (!his.createTime)
|
|
110
|
+
his.createTime = new Date();
|
|
111
|
+
const conn = await this.c();
|
|
112
|
+
try {
|
|
113
|
+
await conn.execute(this.sql('INSERT INTO wf_process_design_his (id, process_design_id, content, create_time, create_user) VALUES (?,?,?,?,?)'), [his.id, his.processDesignId, his.content, his.createTime, his.createUser]);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await this.done(conn);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async listDesignHis(designId) {
|
|
120
|
+
const conn = await this.c();
|
|
121
|
+
try {
|
|
122
|
+
const rows = await conn.fetchAll(this.sql('SELECT id, process_design_id, content, create_time, create_user FROM wf_process_design_his WHERE process_design_id = ? ORDER BY id DESC'), [designId]);
|
|
123
|
+
return rows.map(r => ({
|
|
124
|
+
id: r.id, processDesignId: r.process_design_id,
|
|
125
|
+
content: r.content ? Buffer.from(r.content).toString('utf8') : '',
|
|
126
|
+
createTime: r.create_time, createUser: r.create_user,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
await this.done(conn);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// ── 委托代理 ─────────────────────────────────────────────────────────────
|
|
134
|
+
static SURROGATE_COLS = 'id, process_name, operator, surrogate, start_time, end_time, enabled, create_time, create_user, update_time, update_user';
|
|
135
|
+
async findSurrogateById(id) {
|
|
136
|
+
const conn = await this.c();
|
|
137
|
+
try {
|
|
138
|
+
const row = await conn.fetchOne(this.sql(`SELECT ${JdbcProcessExtRepository.SURROGATE_COLS} FROM wf_process_surrogate WHERE id = ?`), [id]);
|
|
139
|
+
return row ? this.mapSurrogate(row) : null;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
await this.done(conn);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async saveSurrogate(s) {
|
|
146
|
+
if (!s.id)
|
|
147
|
+
s.id = this.idGen.nextId();
|
|
148
|
+
const now = new Date();
|
|
149
|
+
if (!s.createTime)
|
|
150
|
+
s.createTime = now;
|
|
151
|
+
if (!s.updateTime)
|
|
152
|
+
s.updateTime = now;
|
|
153
|
+
if (!s.enabled)
|
|
154
|
+
s.enabled = 1;
|
|
155
|
+
const conn = await this.c();
|
|
156
|
+
try {
|
|
157
|
+
await conn.execute(this.sql('INSERT INTO wf_process_surrogate (id, process_name, operator, surrogate, start_time, ' +
|
|
158
|
+
'end_time, enabled, create_time, create_user, update_time, update_user) VALUES (?,?,?,?,?,?,?,?,?,?,?)'), [s.id, s.processName ?? null, s.operator, s.surrogate, s.startTime ?? null, s.endTime ?? null,
|
|
159
|
+
s.enabled, s.createTime, s.createUser, s.updateTime, s.updateUser]);
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
await this.done(conn);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async updateSurrogate(s) {
|
|
166
|
+
const conn = await this.c();
|
|
167
|
+
try {
|
|
168
|
+
await conn.execute(this.sql('UPDATE wf_process_surrogate SET process_name=?, operator=?, surrogate=?, start_time=?, ' +
|
|
169
|
+
'end_time=?, enabled=?, update_time=?, update_user=? WHERE id=?'), [s.processName ?? null, s.operator, s.surrogate, s.startTime ?? null, s.endTime ?? null,
|
|
170
|
+
s.enabled, new Date(), s.updateUser, s.id]);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
await this.done(conn);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async removeSurrogate(id) {
|
|
177
|
+
const conn = await this.c();
|
|
178
|
+
try {
|
|
179
|
+
await conn.execute(this.sql('DELETE FROM wf_process_surrogate WHERE id=?'), [id]);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
await this.done(conn);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async pageSurrogates(pageNum = 1, pageSize = 10, filters) {
|
|
186
|
+
let sql = `SELECT ${JdbcProcessExtRepository.SURROGATE_COLS} FROM wf_process_surrogate t WHERE 1=1`;
|
|
187
|
+
let countSql = 'SELECT COUNT(*) FROM wf_process_surrogate t WHERE 1=1';
|
|
188
|
+
const args = [];
|
|
189
|
+
const args2 = [];
|
|
190
|
+
for (const [col, val] of Object.entries(filters ?? {})) {
|
|
191
|
+
if (['operator', 'surrogate', 'process_name', 'enabled'].includes(col)) {
|
|
192
|
+
sql += ` AND t.${col} = ?`;
|
|
193
|
+
countSql += ` AND t.${col} = ?`;
|
|
194
|
+
args.push(val);
|
|
195
|
+
args2.push(val);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const conn = await this.c();
|
|
199
|
+
try {
|
|
200
|
+
const countRow = await conn.fetchOne(this.sql(countSql), args2);
|
|
201
|
+
const total = countRow ? Number(Object.values(countRow)[0]) : 0;
|
|
202
|
+
sql += ' ORDER BY t.id DESC LIMIT ? OFFSET ?';
|
|
203
|
+
args.push(pageSize, (pageNum - 1) * pageSize);
|
|
204
|
+
const rows = await conn.fetchAll(this.sql(sql), args);
|
|
205
|
+
return [rows.map(r => this.mapSurrogate(r)), total];
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
await this.done(conn);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async getSurrogate(operator, processName, at = new Date()) {
|
|
212
|
+
const hit = await this.querySurrogate(operator, processName, at);
|
|
213
|
+
if (hit)
|
|
214
|
+
return hit;
|
|
215
|
+
return this.querySurrogate(operator, '', at);
|
|
216
|
+
}
|
|
217
|
+
async querySurrogate(operator, processName, at) {
|
|
218
|
+
let sql = `SELECT ${JdbcProcessExtRepository.SURROGATE_COLS} FROM wf_process_surrogate WHERE operator = ? AND enabled = 1 AND surrogate <> ?`;
|
|
219
|
+
const args = [operator, operator];
|
|
220
|
+
if (!processName) {
|
|
221
|
+
sql += " AND (process_name IS NULL OR process_name = '')";
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
sql += ' AND process_name = ?';
|
|
225
|
+
args.push(processName);
|
|
226
|
+
}
|
|
227
|
+
if (at) {
|
|
228
|
+
sql += ' AND (start_time IS NULL OR start_time <= ?) AND (end_time IS NULL OR end_time >= ?)';
|
|
229
|
+
args.push(at, at);
|
|
230
|
+
}
|
|
231
|
+
sql += ' ORDER BY id DESC LIMIT 1';
|
|
232
|
+
const conn = await this.c();
|
|
233
|
+
try {
|
|
234
|
+
const rows = await conn.fetchAll(this.sql(sql), args);
|
|
235
|
+
return rows.length > 0 ? this.mapSurrogate(rows[0]) : null;
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
await this.done(conn);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// ── 行映射 ───────────────────────────────────────────────────────────────
|
|
242
|
+
mapDesign(row) {
|
|
243
|
+
return {
|
|
244
|
+
id: row.id, name: row.name, displayName: row.display_name, type: row.type,
|
|
245
|
+
icon: row.icon, isDeployed: row.is_deployed, remark: row.remark,
|
|
246
|
+
createTime: row.create_time, createUser: row.create_user,
|
|
247
|
+
updateTime: row.update_time, updateUser: row.update_user,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
mapSurrogate(row) {
|
|
251
|
+
return {
|
|
252
|
+
id: row.id, processName: row.process_name, operator: row.operator, surrogate: row.surrogate,
|
|
253
|
+
startTime: row.start_time, endTime: row.end_time, enabled: row.enabled,
|
|
254
|
+
createTime: row.create_time, createUser: row.create_user,
|
|
255
|
+
updateTime: row.update_time, updateUser: row.update_user,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
package/dist/jdbc/shared.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ export declare class JdbcRepository implements ProcessRepository {
|
|
|
36
36
|
/** 归还非事务连接(事务连接由 withTx 统一释放) */
|
|
37
37
|
private done;
|
|
38
38
|
findDefineById(id: number): Promise<ProcessDefine | null>;
|
|
39
|
+
saveDefine(define: ProcessDefine): Promise<void>;
|
|
40
|
+
updateDefine(define: ProcessDefine): Promise<void>;
|
|
41
|
+
updateDefineState(defineId: number, state: number): Promise<void>;
|
|
42
|
+
removeDefine(defineId: number): Promise<void>;
|
|
43
|
+
findDefineByName(name: string): Promise<ProcessDefine | null>;
|
|
39
44
|
private static INSTANCE_COLS;
|
|
40
45
|
findInstanceById(id: number): Promise<ProcessInstance | null>;
|
|
41
46
|
saveInstance(inst: ProcessInstance): Promise<void>;
|
|
@@ -44,6 +49,8 @@ export declare class JdbcRepository implements ProcessRepository {
|
|
|
44
49
|
findTaskById(taskId: number): Promise<ProcessTask | null>;
|
|
45
50
|
saveTask(task: ProcessTask): Promise<void>;
|
|
46
51
|
updateTask(task: ProcessTask): Promise<void>;
|
|
52
|
+
/** 用指定连接更新任务(实例级联时与实例更新同连接) */
|
|
53
|
+
private updateTaskWithConn;
|
|
47
54
|
private findTasksByState;
|
|
48
55
|
findDoingTasks(instanceId: number, taskNames?: string[]): Promise<ProcessTask[]>;
|
|
49
56
|
findDoneTasks(instanceId: number, taskNames?: string[]): Promise<ProcessTask[]>;
|
package/dist/jdbc/shared.js
CHANGED
|
@@ -99,6 +99,74 @@ export class JdbcRepository {
|
|
|
99
99
|
await this.done(conn);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
+
// 定义写操作(v1.0.1,集成反馈①)。SQL 与 jeeflow-java JdbcProcessRepository 对齐;
|
|
103
|
+
// State/Version 零值按 Java null 语义默认 1。
|
|
104
|
+
async saveDefine(define) {
|
|
105
|
+
if (!define.id)
|
|
106
|
+
define.id = this.idGen.nextId();
|
|
107
|
+
const now = new Date();
|
|
108
|
+
const createTime = define.createTime ?? now;
|
|
109
|
+
const createUser = define.createUser || define.updateUser;
|
|
110
|
+
const conn = await this.c();
|
|
111
|
+
try {
|
|
112
|
+
await conn.execute(this.sql('INSERT INTO wf_process_define (id, name, display_name, type, state, content, version, ' +
|
|
113
|
+
'create_time, create_user, update_time, update_user) VALUES (?,?,?,?,?,?,?,?,?,?,?)'), [define.id, define.name, define.displayName, define.type, define.state || 1,
|
|
114
|
+
define.content, define.version || 1, createTime, createUser,
|
|
115
|
+
define.updateTime ?? now, define.updateUser]);
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
await this.done(conn);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async updateDefine(define) {
|
|
122
|
+
const conn = await this.c();
|
|
123
|
+
try {
|
|
124
|
+
await conn.execute(this.sql('UPDATE wf_process_define SET name=?, display_name=?, type=?, state=?, content=?, ' +
|
|
125
|
+
'version=?, update_time=?, update_user=? WHERE id=?'), [define.name, define.displayName, define.type, define.state || 1,
|
|
126
|
+
define.content, define.version || 1, new Date(), define.updateUser, define.id]);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await this.done(conn);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async updateDefineState(defineId, state) {
|
|
133
|
+
const conn = await this.c();
|
|
134
|
+
try {
|
|
135
|
+
await conn.execute(this.sql('UPDATE wf_process_define SET state=?, update_time=? WHERE id=?'), [state, new Date(), defineId]);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
await this.done(conn);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async removeDefine(defineId) {
|
|
142
|
+
const conn = await this.c();
|
|
143
|
+
try {
|
|
144
|
+
await conn.execute(this.sql('DELETE FROM wf_process_define WHERE id=?'), [defineId]);
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await this.done(conn);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// findDefineByName 按流程编码查最新一条定义(v1.1.0,deploy 版本管理用)
|
|
151
|
+
async findDefineByName(name) {
|
|
152
|
+
const conn = await this.c();
|
|
153
|
+
try {
|
|
154
|
+
const row = await conn.fetchOne(this.sql('SELECT id, name, display_name, type, state, content, version, ' +
|
|
155
|
+
'create_time, create_user, update_time, update_user FROM wf_process_define WHERE name = ? ORDER BY version DESC LIMIT 1'), [name]);
|
|
156
|
+
if (!row)
|
|
157
|
+
return null;
|
|
158
|
+
return {
|
|
159
|
+
id: row.id, name: row.name, displayName: row.display_name, type: row.type,
|
|
160
|
+
state: row.state,
|
|
161
|
+
content: row.content ? Buffer.from(row.content).toString('utf8') : '',
|
|
162
|
+
version: row.version, createTime: row.create_time, createUser: row.create_user,
|
|
163
|
+
updateTime: row.update_time, updateUser: row.update_user,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
await this.done(conn);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
102
170
|
// ── ProcessInstance ───────────────────────────────────────────────────────
|
|
103
171
|
static INSTANCE_COLS = 'id, parent_id, process_define_id, state, parent_node_name, business_no, ' +
|
|
104
172
|
'operator, expire_time, variable, create_time, create_user, update_time, update_user';
|
|
@@ -144,6 +212,11 @@ export class JdbcRepository {
|
|
|
144
212
|
'operator=?, expire_time=?, variable=?, update_time=?, update_user=? WHERE id=?'), [inst.state, inst.parentNodeName ?? '', inst.businessNo ?? '', inst.operator,
|
|
145
213
|
inst.expireTime ?? null, JSON.stringify(inst.variables ?? {}),
|
|
146
214
|
inst.updateTime, inst.updateUser, inst.id]);
|
|
215
|
+
// v1.0.1:级联持久化聚合根内任务状态变更(同连接,spec §7.4)
|
|
216
|
+
for (const task of inst.tasks) {
|
|
217
|
+
if (task.id)
|
|
218
|
+
await this.updateTaskWithConn(conn, task);
|
|
219
|
+
}
|
|
147
220
|
}
|
|
148
221
|
finally {
|
|
149
222
|
await this.done(conn);
|
|
@@ -187,14 +260,18 @@ export class JdbcRepository {
|
|
|
187
260
|
async updateTask(task) {
|
|
188
261
|
const conn = await this.c();
|
|
189
262
|
try {
|
|
190
|
-
await
|
|
191
|
-
'variable=?, update_time=?, update_user=? WHERE id=?'), [task.taskState, task.actorId ?? '', task.finishTime ?? null, task.expireTime ?? null,
|
|
192
|
-
JSON.stringify(task.variables ?? {}), task.updateTime, task.updateUser, task.id]);
|
|
263
|
+
await this.updateTaskWithConn(conn, task);
|
|
193
264
|
}
|
|
194
265
|
finally {
|
|
195
266
|
await this.done(conn);
|
|
196
267
|
}
|
|
197
268
|
}
|
|
269
|
+
/** 用指定连接更新任务(实例级联时与实例更新同连接) */
|
|
270
|
+
async updateTaskWithConn(conn, task) {
|
|
271
|
+
await conn.execute(this.sql('UPDATE wf_process_task SET task_state=?, operator=?, finish_time=?, expire_time=?, ' +
|
|
272
|
+
'variable=?, update_time=?, update_user=? WHERE id=?'), [task.taskState, task.actorId ?? '', task.finishTime ?? null, task.expireTime ?? null,
|
|
273
|
+
JSON.stringify(task.variables ?? {}), task.updateTime, task.updateUser, task.id]);
|
|
274
|
+
}
|
|
198
275
|
async findTasksByState(instanceId, state, taskNames) {
|
|
199
276
|
let sql = `SELECT ${JdbcRepository.TASK_COLS} FROM wf_process_task WHERE process_instance_id = ?`;
|
|
200
277
|
const args = [instanceId];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ProcessDesign, ProcessDesignHis, ProcessSurrogate } from './model.js';
|
|
2
|
+
import type { ProcessExtRepository } from './spi.js';
|
|
3
|
+
export declare class MemoryExtRepository implements ProcessExtRepository {
|
|
4
|
+
private designs;
|
|
5
|
+
private designHis;
|
|
6
|
+
private surrogates;
|
|
7
|
+
private seq;
|
|
8
|
+
findDesignById(id: number): Promise<ProcessDesign | null>;
|
|
9
|
+
saveDesign(d: ProcessDesign): Promise<void>;
|
|
10
|
+
updateDesign(d: ProcessDesign): Promise<void>;
|
|
11
|
+
removeDesign(id: number): Promise<void>;
|
|
12
|
+
pageDesigns(_pageNum?: number, _pageSize?: number, _filters?: Record<string, any>): Promise<[ProcessDesign[], number]>;
|
|
13
|
+
saveDesignHis(his: ProcessDesignHis): Promise<void>;
|
|
14
|
+
listDesignHis(designId: number): Promise<ProcessDesignHis[]>;
|
|
15
|
+
findSurrogateById(id: number): Promise<ProcessSurrogate | null>;
|
|
16
|
+
saveSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
17
|
+
updateSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
18
|
+
removeSurrogate(id: number): Promise<void>;
|
|
19
|
+
pageSurrogates(_pageNum?: number, _pageSize?: number, _filters?: Record<string, any>): Promise<[ProcessSurrogate[], number]>;
|
|
20
|
+
getSurrogate(operator: string, processName: string, at?: Date): Promise<ProcessSurrogate | null>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// 扩展仓储内存实现(v1.1.0,测试/演示用)
|
|
2
|
+
export class MemoryExtRepository {
|
|
3
|
+
designs = new Map();
|
|
4
|
+
designHis = new Map();
|
|
5
|
+
surrogates = new Map();
|
|
6
|
+
seq = 1;
|
|
7
|
+
// ── 流程设计 ──
|
|
8
|
+
async findDesignById(id) { return this.designs.get(id) ?? null; }
|
|
9
|
+
async saveDesign(d) {
|
|
10
|
+
if (!d.id)
|
|
11
|
+
d.id = this.seq++;
|
|
12
|
+
const now = new Date();
|
|
13
|
+
if (!d.createTime)
|
|
14
|
+
d.createTime = now;
|
|
15
|
+
if (!d.updateTime)
|
|
16
|
+
d.updateTime = now;
|
|
17
|
+
this.designs.set(d.id, { ...d });
|
|
18
|
+
}
|
|
19
|
+
async updateDesign(d) {
|
|
20
|
+
d.updateTime = new Date();
|
|
21
|
+
this.designs.set(d.id, { ...d });
|
|
22
|
+
}
|
|
23
|
+
async removeDesign(id) {
|
|
24
|
+
this.designs.delete(id);
|
|
25
|
+
this.designHis.delete(id);
|
|
26
|
+
}
|
|
27
|
+
async pageDesigns(_pageNum = 1, _pageSize = 10, _filters) {
|
|
28
|
+
return [[...this.designs.values()], this.designs.size];
|
|
29
|
+
}
|
|
30
|
+
// ── 设计历史 ──
|
|
31
|
+
async saveDesignHis(his) {
|
|
32
|
+
if (!his.id)
|
|
33
|
+
his.id = this.seq++;
|
|
34
|
+
if (!his.createTime)
|
|
35
|
+
his.createTime = new Date();
|
|
36
|
+
const list = this.designHis.get(his.processDesignId) ?? [];
|
|
37
|
+
list.unshift({ ...his });
|
|
38
|
+
this.designHis.set(his.processDesignId, list);
|
|
39
|
+
}
|
|
40
|
+
async listDesignHis(designId) {
|
|
41
|
+
return this.designHis.get(designId) ?? [];
|
|
42
|
+
}
|
|
43
|
+
// ── 委托代理 ──
|
|
44
|
+
async findSurrogateById(id) { return this.surrogates.get(id) ?? null; }
|
|
45
|
+
async saveSurrogate(s) {
|
|
46
|
+
if (!s.id)
|
|
47
|
+
s.id = this.seq++;
|
|
48
|
+
const now = new Date();
|
|
49
|
+
if (!s.createTime)
|
|
50
|
+
s.createTime = now;
|
|
51
|
+
if (!s.updateTime)
|
|
52
|
+
s.updateTime = now;
|
|
53
|
+
if (!s.enabled)
|
|
54
|
+
s.enabled = 1;
|
|
55
|
+
this.surrogates.set(s.id, { ...s });
|
|
56
|
+
}
|
|
57
|
+
async updateSurrogate(s) {
|
|
58
|
+
s.updateTime = new Date();
|
|
59
|
+
this.surrogates.set(s.id, { ...s });
|
|
60
|
+
}
|
|
61
|
+
async removeSurrogate(id) {
|
|
62
|
+
this.surrogates.delete(id);
|
|
63
|
+
}
|
|
64
|
+
async pageSurrogates(_pageNum = 1, _pageSize = 10, _filters) {
|
|
65
|
+
return [[...this.surrogates.values()], this.surrogates.size];
|
|
66
|
+
}
|
|
67
|
+
async getSurrogate(operator, processName, at = new Date()) {
|
|
68
|
+
let fallback = null;
|
|
69
|
+
for (const s of this.surrogates.values()) {
|
|
70
|
+
if (s.operator !== operator || s.enabled !== 1)
|
|
71
|
+
continue;
|
|
72
|
+
if (s.startTime && s.startTime > at)
|
|
73
|
+
continue;
|
|
74
|
+
if (s.endTime && s.endTime < at)
|
|
75
|
+
continue;
|
|
76
|
+
if (s.processName === processName && processName)
|
|
77
|
+
return { ...s };
|
|
78
|
+
if ((!s.processName || s.processName === processName) && !fallback)
|
|
79
|
+
fallback = s;
|
|
80
|
+
}
|
|
81
|
+
return fallback ? { ...fallback } : null;
|
|
82
|
+
}
|
|
83
|
+
}
|
package/dist/memory.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare class MemoryRepository implements ProcessRepository {
|
|
|
9
9
|
private seq;
|
|
10
10
|
addDefine(def: ProcessDefine): void;
|
|
11
11
|
findDefineById(id: number): Promise<ProcessDefine | null>;
|
|
12
|
+
findDefineByName(name: string): Promise<ProcessDefine | null>;
|
|
13
|
+
saveDefine(def: ProcessDefine): Promise<void>;
|
|
14
|
+
updateDefine(def: ProcessDefine): Promise<void>;
|
|
15
|
+
updateDefineState(defineId: number, state: number): Promise<void>;
|
|
16
|
+
removeDefine(defineId: number): Promise<void>;
|
|
12
17
|
saveInstance(inst: ProcessInstance): Promise<void>;
|
|
13
18
|
updateInstance(inst: ProcessInstance): Promise<void>;
|
|
14
19
|
findInstanceById(id: number): Promise<ProcessInstance | null>;
|
package/dist/memory.js
CHANGED
|
@@ -11,6 +11,32 @@ export class MemoryRepository {
|
|
|
11
11
|
this.defines.set(def.id, def);
|
|
12
12
|
}
|
|
13
13
|
async findDefineById(id) { return this.defines.get(id) ?? null; }
|
|
14
|
+
// findDefineByName 按流程编码查最新一条定义(id 倒序取首条,v1.1.0)
|
|
15
|
+
async findDefineByName(name) {
|
|
16
|
+
let latest = null;
|
|
17
|
+
for (const d of this.defines.values()) {
|
|
18
|
+
if (d.name === name && (!latest || d.id > latest.id))
|
|
19
|
+
latest = d;
|
|
20
|
+
}
|
|
21
|
+
return latest;
|
|
22
|
+
}
|
|
23
|
+
// ── 定义写操作(v1.0.1,对齐 SPI)──
|
|
24
|
+
async saveDefine(def) {
|
|
25
|
+
if (!def.id)
|
|
26
|
+
def.id = this.seq++;
|
|
27
|
+
this.defines.set(def.id, def);
|
|
28
|
+
}
|
|
29
|
+
async updateDefine(def) {
|
|
30
|
+
this.defines.set(def.id, def);
|
|
31
|
+
}
|
|
32
|
+
async updateDefineState(defineId, state) {
|
|
33
|
+
const d = this.defines.get(defineId);
|
|
34
|
+
if (d)
|
|
35
|
+
d.state = state;
|
|
36
|
+
}
|
|
37
|
+
async removeDefine(defineId) {
|
|
38
|
+
this.defines.delete(defineId);
|
|
39
|
+
}
|
|
14
40
|
async saveInstance(inst) {
|
|
15
41
|
if (!inst.id)
|
|
16
42
|
inst.id = this.seq++;
|
|
@@ -22,6 +48,16 @@ export class MemoryRepository {
|
|
|
22
48
|
const cp = cloneInstance(inst);
|
|
23
49
|
cp.tasks = [];
|
|
24
50
|
this.instances.set(inst.id, cp);
|
|
51
|
+
// v1.0.1:级联保存聚合根内任务状态变更
|
|
52
|
+
for (const t of inst.tasks) {
|
|
53
|
+
if (!t.id)
|
|
54
|
+
continue;
|
|
55
|
+
const tc = cloneTask(t);
|
|
56
|
+
tc.actorIds = [];
|
|
57
|
+
this.tasks.set(t.id, tc);
|
|
58
|
+
if (t.actorIds.length)
|
|
59
|
+
this.actors.set(t.id, [...t.actorIds]);
|
|
60
|
+
}
|
|
25
61
|
}
|
|
26
62
|
async findInstanceById(id) {
|
|
27
63
|
const inst = this.instances.get(id);
|
package/dist/model.d.ts
CHANGED
|
@@ -44,6 +44,39 @@ export interface ProcessDefine {
|
|
|
44
44
|
updateTime: Date;
|
|
45
45
|
updateUser: string;
|
|
46
46
|
}
|
|
47
|
+
export interface ProcessDesign {
|
|
48
|
+
id: number;
|
|
49
|
+
name: string;
|
|
50
|
+
displayName: string;
|
|
51
|
+
type: string;
|
|
52
|
+
icon?: string;
|
|
53
|
+
isDeployed: number;
|
|
54
|
+
remark?: string;
|
|
55
|
+
createTime: Date;
|
|
56
|
+
createUser: string;
|
|
57
|
+
updateTime: Date;
|
|
58
|
+
updateUser: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ProcessDesignHis {
|
|
61
|
+
id: number;
|
|
62
|
+
processDesignId: number;
|
|
63
|
+
content: Uint8Array | string;
|
|
64
|
+
createTime: Date;
|
|
65
|
+
createUser: string;
|
|
66
|
+
}
|
|
67
|
+
export interface ProcessSurrogate {
|
|
68
|
+
id: number;
|
|
69
|
+
processName?: string;
|
|
70
|
+
operator: string;
|
|
71
|
+
surrogate: string;
|
|
72
|
+
startTime?: Date;
|
|
73
|
+
endTime?: Date;
|
|
74
|
+
enabled: number;
|
|
75
|
+
createTime: Date;
|
|
76
|
+
createUser: string;
|
|
77
|
+
updateTime: Date;
|
|
78
|
+
updateUser: string;
|
|
79
|
+
}
|
|
47
80
|
export declare enum InstanceState {
|
|
48
81
|
Doing = 10,
|
|
49
82
|
Done = 20,
|
package/dist/spi.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import type { ProcessDefine, ProcessInstance, ProcessTask, UserInfo } from './model.js';
|
|
1
|
+
import type { ProcessDefine, ProcessDesign, ProcessDesignHis, ProcessInstance, ProcessSurrogate, ProcessTask, UserInfo } from './model.js';
|
|
2
2
|
export interface ProcessRepository {
|
|
3
3
|
findDefineById(id: number): Promise<ProcessDefine | null>;
|
|
4
|
+
findDefineByName(name: string): Promise<ProcessDefine | null>;
|
|
5
|
+
saveDefine(define: ProcessDefine): Promise<void>;
|
|
6
|
+
updateDefine(define: ProcessDefine): Promise<void>;
|
|
7
|
+
updateDefineState(defineId: number, state: number): Promise<void>;
|
|
8
|
+
removeDefine(defineId: number): Promise<void>;
|
|
4
9
|
findInstanceById(id: number): Promise<ProcessInstance | null>;
|
|
5
10
|
saveInstance(inst: ProcessInstance): Promise<void>;
|
|
6
11
|
updateInstance(inst: ProcessInstance): Promise<void>;
|
|
@@ -25,3 +30,18 @@ export interface IDGenerator {
|
|
|
25
30
|
export interface ExpressionEvaluator {
|
|
26
31
|
eval(expr: string, vars: Record<string, any>): Promise<any>;
|
|
27
32
|
}
|
|
33
|
+
export interface ProcessExtRepository {
|
|
34
|
+
findDesignById(id: number): Promise<ProcessDesign | null>;
|
|
35
|
+
saveDesign(d: ProcessDesign): Promise<void>;
|
|
36
|
+
updateDesign(d: ProcessDesign): Promise<void>;
|
|
37
|
+
removeDesign(id: number): Promise<void>;
|
|
38
|
+
pageDesigns(pageNum?: number, pageSize?: number, filters?: Record<string, any>): Promise<[ProcessDesign[], number]>;
|
|
39
|
+
saveDesignHis(his: ProcessDesignHis): Promise<void>;
|
|
40
|
+
listDesignHis(designId: number): Promise<ProcessDesignHis[]>;
|
|
41
|
+
findSurrogateById(id: number): Promise<ProcessSurrogate | null>;
|
|
42
|
+
saveSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
43
|
+
updateSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
44
|
+
removeSurrogate(id: number): Promise<void>;
|
|
45
|
+
pageSurrogates(pageNum?: number, pageSize?: number, filters?: Record<string, any>): Promise<[ProcessSurrogate[], number]>;
|
|
46
|
+
getSurrogate(operator: string, processName: string, at?: Date): Promise<ProcessSurrogate | null>;
|
|
47
|
+
}
|