@stalfh233/omc-fake-platform 0.0.0-stage → 0.4.39
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 +2 -2
- package/dist/app.d.ts +3 -0
- package/dist/app.js +44 -0
- package/dist/b2-registration.d.ts +2 -0
- package/dist/b2-registration.js +619 -0
- package/dist/businessrule.d.ts +3 -0
- package/dist/businessrule.js +241 -0
- package/dist/datarule.d.ts +2 -0
- package/dist/datarule.js +71 -0
- package/dist/dictionary.d.ts +2 -0
- package/dist/dictionary.js +107 -0
- package/dist/environment.d.ts +6 -0
- package/dist/environment.js +29 -0
- package/dist/field.d.ts +3 -0
- package/dist/field.js +166 -0
- package/dist/form.d.ts +3 -0
- package/dist/form.js +100 -0
- package/dist/http-server.d.ts +8 -0
- package/dist/http-server.js +64 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +120 -0
- package/dist/list-view.d.ts +3 -0
- package/dist/list-view.js +288 -0
- package/dist/model.d.ts +3 -0
- package/dist/model.js +135 -0
- package/dist/online-js.d.ts +3 -0
- package/dist/online-js.js +17 -0
- package/dist/report.d.ts +2 -0
- package/dist/report.js +252 -0
- package/dist/routes.d.ts +2 -0
- package/dist/routes.js +46 -0
- package/dist/rule-lifecycle.d.ts +7 -0
- package/dist/rule-lifecycle.js +36 -0
- package/dist/runtime-data.d.ts +2 -0
- package/dist/runtime-data.js +366 -0
- package/dist/state.d.ts +400 -0
- package/dist/state.js +66 -0
- package/dist/workflow.d.ts +39 -0
- package/dist/workflow.js +363 -0
- package/package.json +24 -4
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { businessRefusal, malformedEnvelope, NOT_HANDLED } from "./state.js";
|
|
2
|
+
const PENDING_STATES = new Set(["NOTSTARTED", "INPROGRESS"]);
|
|
3
|
+
const ACTIVITY_TYPES = new Set(["START", "END", "CONNECTION", "PARTICIPANT", "SUB_INSTANCE", "CIRCULATE", "SYSTEM_ACTIVITY", "AGENT_ACTIVITY"]);
|
|
4
|
+
const POINT = /^-?\d+(?:\.\d+)?,\s-?\d+(?:\.\d+)?$/;
|
|
5
|
+
/**
|
|
6
|
+
* Live 8.6.26 fidelity (2026-09-17 probe): workflow/validate and /publish
|
|
7
|
+
* answer HTTP 200 + errcode 0 and put the truth in `data` as
|
|
8
|
+
* ValidateMessage[]. The originate (first PARTICIPANT) node's `participant`
|
|
9
|
+
* must be the platform keyword `"{Originator}"`; a plain value ("admin")
|
|
10
|
+
* answers `401035 <activityName> ERROR` and the flow never goes live.
|
|
11
|
+
* `"{Creator}"` on a non-originate participant node is a `401062` WARN that
|
|
12
|
+
* does not block.
|
|
13
|
+
*/
|
|
14
|
+
function validateWorkflowParticipants(activities) {
|
|
15
|
+
if (!Array.isArray(activities))
|
|
16
|
+
return [];
|
|
17
|
+
const rows = activities;
|
|
18
|
+
const participants = rows.filter((activity) => String(activity?.activityType ?? "") === "PARTICIPANT");
|
|
19
|
+
const messages = [];
|
|
20
|
+
const originate = participants[0];
|
|
21
|
+
if (originate && String(originate.participant ?? "") !== "{Originator}")
|
|
22
|
+
messages.push({ errCode: 401035, errContent: originate.activityName ?? originate.activityCode ?? "", errMsg: null, errorLevel: "ERROR" });
|
|
23
|
+
for (const activity of participants.slice(1)) {
|
|
24
|
+
if (String(activity.participant ?? "") === "{Creator}")
|
|
25
|
+
messages.push({ errCode: 401062, errContent: activity.activityName ?? activity.activityCode ?? "", errMsg: null, errorLevel: "WARN" });
|
|
26
|
+
}
|
|
27
|
+
return messages;
|
|
28
|
+
}
|
|
29
|
+
function invalidRenderShape(body) {
|
|
30
|
+
if (!Array.isArray(body.activities))
|
|
31
|
+
return "activities";
|
|
32
|
+
const codes = new Set();
|
|
33
|
+
for (const activity of body.activities) {
|
|
34
|
+
const record = activity;
|
|
35
|
+
const code = String(record?.activityCode ?? "").trim();
|
|
36
|
+
const type = String(record?.activityType ?? "").trim();
|
|
37
|
+
if (!code || codes.has(code) || !ACTIVITY_TYPES.has(type))
|
|
38
|
+
return "activities";
|
|
39
|
+
codes.add(code);
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(body.rules))
|
|
42
|
+
return "rules";
|
|
43
|
+
for (const rule of body.rules) {
|
|
44
|
+
const record = rule;
|
|
45
|
+
const pre = String(record?.preActivityCode ?? "");
|
|
46
|
+
const post = String(record?.postActivityCode ?? "");
|
|
47
|
+
const points = record?.points;
|
|
48
|
+
if (!codes.has(pre) || !codes.has(post) || !Array.isArray(points) || points.length === 0 || points.some((point) => typeof point !== "string" || !POINT.test(point)))
|
|
49
|
+
return "rules";
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Spawn the two work items a workflow start produces: the originator fill item
|
|
55
|
+
* (already FINISHED — the start submit is the fill) and the pending approval
|
|
56
|
+
* item that `workitem.list` must surface for `data.submit`.
|
|
57
|
+
*/
|
|
58
|
+
export function startWorkflowInstance(state, input) {
|
|
59
|
+
const sequence = state.workItems.size + 1;
|
|
60
|
+
const instanceId = `wf-${sequence}`;
|
|
61
|
+
const fillId = `wi-${sequence}`;
|
|
62
|
+
const approveId = `wi-${sequence + 1}`;
|
|
63
|
+
state.workItems.set(fillId, {
|
|
64
|
+
id: fillId,
|
|
65
|
+
instanceId,
|
|
66
|
+
activityCode: "fill",
|
|
67
|
+
activityName: "填写申请单",
|
|
68
|
+
participant: "tester",
|
|
69
|
+
state: "FINISHED",
|
|
70
|
+
workflowCode: input.workflowCode,
|
|
71
|
+
schemaCode: input.schemaCode,
|
|
72
|
+
bizObjectId: input.bizObjectId,
|
|
73
|
+
});
|
|
74
|
+
state.workItems.set(approveId, {
|
|
75
|
+
id: approveId,
|
|
76
|
+
instanceId,
|
|
77
|
+
activityCode: "approve",
|
|
78
|
+
activityName: "审批",
|
|
79
|
+
participant: "tester",
|
|
80
|
+
state: "INPROGRESS",
|
|
81
|
+
workflowCode: input.workflowCode,
|
|
82
|
+
schemaCode: input.schemaCode,
|
|
83
|
+
bizObjectId: input.bizObjectId,
|
|
84
|
+
});
|
|
85
|
+
return { workflowInstanceId: instanceId, workItemId: approveId };
|
|
86
|
+
}
|
|
87
|
+
/** Complete a pending work item (approval submit). Returns false if unknown. */
|
|
88
|
+
export function completeWorkItem(state, workItemId) {
|
|
89
|
+
const item = state.workItems.get(workItemId);
|
|
90
|
+
if (!item)
|
|
91
|
+
return false;
|
|
92
|
+
item.state = "FINISHED";
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Portal draft-save shape (finishStart=FALSE): one instance in DRAFT with a
|
|
97
|
+
* single PENDING start work item. Submitting that item (startWorkflowDraft's
|
|
98
|
+
* workItemId) is what advances the instance — see startWorkflowInstance for
|
|
99
|
+
* the finishStart=TRUE twin.
|
|
100
|
+
*/
|
|
101
|
+
export function startWorkflowDraft(state, input) {
|
|
102
|
+
const sequence = state.workItems.size + 1;
|
|
103
|
+
const instanceId = `wf-${sequence}`;
|
|
104
|
+
const startId = `wi-${sequence}`;
|
|
105
|
+
state.workItems.set(startId, {
|
|
106
|
+
id: startId,
|
|
107
|
+
instanceId,
|
|
108
|
+
activityCode: "fill",
|
|
109
|
+
activityName: "填写申请单",
|
|
110
|
+
participant: "tester",
|
|
111
|
+
state: "INPROGRESS",
|
|
112
|
+
workflowCode: input.workflowCode,
|
|
113
|
+
schemaCode: input.schemaCode,
|
|
114
|
+
bizObjectId: input.bizObjectId,
|
|
115
|
+
isStart: true,
|
|
116
|
+
});
|
|
117
|
+
return { workflowInstanceId: instanceId, workItemId: startId };
|
|
118
|
+
}
|
|
119
|
+
/** After the START work item is submitted, the next (approval) activity spawns a pending todo. */
|
|
120
|
+
export function spawnApprovalWorkItem(state, input) {
|
|
121
|
+
const approveId = `wi-${state.workItems.size + 1}`;
|
|
122
|
+
state.workItems.set(approveId, {
|
|
123
|
+
id: approveId,
|
|
124
|
+
instanceId: input.instanceId,
|
|
125
|
+
activityCode: "approve",
|
|
126
|
+
activityName: "审批",
|
|
127
|
+
participant: "tester",
|
|
128
|
+
state: "INPROGRESS",
|
|
129
|
+
workflowCode: input.workflowCode,
|
|
130
|
+
schemaCode: input.schemaCode,
|
|
131
|
+
bizObjectId: input.bizObjectId,
|
|
132
|
+
});
|
|
133
|
+
return approveId;
|
|
134
|
+
}
|
|
135
|
+
function toWorkItemVO(item) {
|
|
136
|
+
return {
|
|
137
|
+
id: item.id,
|
|
138
|
+
instanceId: item.instanceId,
|
|
139
|
+
activityCode: item.activityCode,
|
|
140
|
+
activityName: item.activityName,
|
|
141
|
+
state: item.state,
|
|
142
|
+
workflowCode: item.workflowCode,
|
|
143
|
+
schemaCode: item.schemaCode,
|
|
144
|
+
participant: item.participant,
|
|
145
|
+
participantName: item.participantName ?? item.participant,
|
|
146
|
+
originator: item.originator,
|
|
147
|
+
sequenceNo: item.sequenceNo,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/** W7-S29-greenfield lane: workflow template authoring + runtime work-item query. Twin of src/lanes/workflow.ts. */
|
|
151
|
+
export const workflowRoute = (ctx, input) => {
|
|
152
|
+
const q = input.query ?? {};
|
|
153
|
+
const body = (input.body ?? {});
|
|
154
|
+
switch (input.path) {
|
|
155
|
+
case "/api/api/workflow/create": {
|
|
156
|
+
const code = String(body.workflowCode ?? body.code ?? "");
|
|
157
|
+
const name = String(body.workflowName ?? body.name ?? code);
|
|
158
|
+
const schemaCode = String(body.schemaCode ?? "");
|
|
159
|
+
// Ticket 76 live fidelity: creating a workflow when the SCHEMA already
|
|
160
|
+
// has one answers an envelope with NO numeric errcode (live:
|
|
161
|
+
// "envelope for /api/api/workflow/create has no numeric errcode") — the
|
|
162
|
+
// tool must decode it as a duplicate-create, not a malformed failure.
|
|
163
|
+
if ([...ctx.state.workflows.values()].some((wf) => wf.schemaCode === schemaCode) && !ctx.state.workflows.has(code))
|
|
164
|
+
return malformedEnvelope({ workflowCode: code, workflowName: name, schemaCode, exist: true });
|
|
165
|
+
if (!ctx.state.workflows.has(code)) {
|
|
166
|
+
// Ticket 112 platform fidelity: the real create auto-generates a
|
|
167
|
+
// full draft (START → PARTICIPANT 填写申请单 → END with canvas rules;
|
|
168
|
+
// WorkflowTemplateController update @ApiImplicitParam example) — the
|
|
169
|
+
// fake seeds the same platform-shaped template so the merge path has
|
|
170
|
+
// real activity boxes and rule shapes to echo.
|
|
171
|
+
ctx.state.workflows.set(code, {
|
|
172
|
+
code,
|
|
173
|
+
name,
|
|
174
|
+
schemaCode,
|
|
175
|
+
template: {
|
|
176
|
+
workflowCode: code,
|
|
177
|
+
name,
|
|
178
|
+
workflowName: name,
|
|
179
|
+
schemaCode,
|
|
180
|
+
// Live create seeds templateType DRAFT ("SAVE" is not a
|
|
181
|
+
// WorkflowTemplateStatus member — S29 contract).
|
|
182
|
+
templateType: "DRAFT",
|
|
183
|
+
activities: [
|
|
184
|
+
{ activityCode: "Activity1", activityType: "START", activityName: "开始", x: 327, y: 36, width: 158, height: 40 },
|
|
185
|
+
{ activityCode: "Activity2", activityType: "PARTICIPANT", activityName: "填写申请单", participant: "{Originator}", x: 327, y: 116, width: 158, height: 40 },
|
|
186
|
+
{ activityCode: "Activity3", activityType: "END", activityName: "结束", x: 327, y: 196, width: 158, height: 40 },
|
|
187
|
+
],
|
|
188
|
+
rules: [
|
|
189
|
+
{ preActivityCode: "Activity1", postActivityCode: "Activity2", points: ["406, 76", "406, 116"] },
|
|
190
|
+
{ preActivityCode: "Activity2", postActivityCode: "Activity3", points: ["406, 156", "406, 196"] },
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
published: null,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return { code };
|
|
197
|
+
}
|
|
198
|
+
case "/api/api/workflow/isworkflow": {
|
|
199
|
+
// WorkflowTemplateController.isWorkFlow(schemaCode): any header for the
|
|
200
|
+
// schema answers true.
|
|
201
|
+
const schemaCode = String(q.schemaCode ?? "");
|
|
202
|
+
return [...ctx.state.workflows.values()].some((wf) => wf.schemaCode === schemaCode);
|
|
203
|
+
}
|
|
204
|
+
case "/api/api/workflow/getWorkflow": {
|
|
205
|
+
// WorkflowTemplateController.getWorkflow(schemaCode): the published
|
|
206
|
+
// template for the schema (carries workflowCode), or null when the model
|
|
207
|
+
// has none. Used to auto-start a workflow-backed data.submit.
|
|
208
|
+
const schemaCode = String(q.schemaCode ?? "");
|
|
209
|
+
const wf = [...ctx.state.workflows.values()].find((candidate) => candidate.schemaCode === schemaCode);
|
|
210
|
+
if (!wf)
|
|
211
|
+
return null;
|
|
212
|
+
const template = (wf.published ?? wf.template);
|
|
213
|
+
return { ...template, workflowCode: wf.code };
|
|
214
|
+
}
|
|
215
|
+
case "/api/api/workflow/get_header": {
|
|
216
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
217
|
+
// Round-2 live fidelity (BUG-05): these endpoints answer 401001
|
|
218
|
+
// 流程不存在! for an ABSENT workflow rather than a null payload.
|
|
219
|
+
if (!wf)
|
|
220
|
+
return businessRefusal(401001, "流程不存在!");
|
|
221
|
+
return { code: wf.code, name: wf.name };
|
|
222
|
+
}
|
|
223
|
+
case "/api/api/workflow/get_draft": {
|
|
224
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
225
|
+
if (!wf)
|
|
226
|
+
return businessRefusal(401001, "流程不存在!");
|
|
227
|
+
return wf.template;
|
|
228
|
+
}
|
|
229
|
+
case "/api/api/workflow/get_published": {
|
|
230
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
231
|
+
// Live fidelity: like get_header/get_draft, an ABSENT workflow answers
|
|
232
|
+
// 401001 流程不存在! rather than a null payload; the tool degrades that
|
|
233
|
+
// to exists:false. Ticket 77: an UNPUBLISHED workflow still answers the
|
|
234
|
+
// DRAFT shape here — data presence is not publish evidence. The
|
|
235
|
+
// published face carries the templateType PUBLISH marker.
|
|
236
|
+
if (!wf)
|
|
237
|
+
return businessRefusal(401001, "流程不存在!");
|
|
238
|
+
return wf.published ?? wf.template ?? null;
|
|
239
|
+
}
|
|
240
|
+
case "/api/api/workflow/update": {
|
|
241
|
+
const code = String(body.workflowCode ?? q.workflowCode ?? "");
|
|
242
|
+
const wf = ctx.state.workflows.get(code);
|
|
243
|
+
if (!wf)
|
|
244
|
+
return null;
|
|
245
|
+
// Ticket 112 platform fidelity (WorkflowTemplateUtil.java:90-171): an
|
|
246
|
+
// illegal templateType ("BusinessProcess" is not a
|
|
247
|
+
// WorkflowTemplateStatus member — valueOf at :136) or an activities
|
|
248
|
+
// element without a type makes the converter swallow the exception
|
|
249
|
+
// into a PARTIAL model; the save chain then fails with errcode 50000.
|
|
250
|
+
if (body.templateType === "BusinessProcess")
|
|
251
|
+
return businessRefusal(50000, "服务异常");
|
|
252
|
+
if (Array.isArray(body.activities) &&
|
|
253
|
+
body.activities.some((activity) => {
|
|
254
|
+
const record = activity;
|
|
255
|
+
const type = record != null && typeof record === "object" ? (record.type ?? record.activityType) : undefined;
|
|
256
|
+
return type === undefined || type === null || String(type).trim() === "";
|
|
257
|
+
}))
|
|
258
|
+
return businessRefusal(50000, "服务异常");
|
|
259
|
+
if (body.activities !== undefined && invalidRenderShape(body))
|
|
260
|
+
return businessRefusal(50000, "服务异常");
|
|
261
|
+
// Platform fidelity (live 2026-09-23; bench12/13/15): an existing
|
|
262
|
+
// activityCode cannot be RENAMED or RETYPED — the stored name/type win.
|
|
263
|
+
// A caller that wants a different name/type must send it under a fresh
|
|
264
|
+
// code (the tool reconciles this before the wire); re-sending the same
|
|
265
|
+
// code with a changed name is a silent no-op on the platform, so the fake
|
|
266
|
+
// must reproduce it rather than store the body verbatim.
|
|
267
|
+
const stored = wf.template.activities;
|
|
268
|
+
const storedByCode = new Map((Array.isArray(stored) ? stored : []).map((activity) => [String(activity.activityCode ?? ""), activity]));
|
|
269
|
+
const pinned = Array.isArray(body.activities)
|
|
270
|
+
? {
|
|
271
|
+
...body,
|
|
272
|
+
activities: body.activities.map((activity) => {
|
|
273
|
+
const prior = storedByCode.get(String(activity.activityCode ?? ""));
|
|
274
|
+
return prior
|
|
275
|
+
? { ...activity, activityName: prior.activityName, i18nMessage: prior.i18nMessage, activityType: prior.activityType }
|
|
276
|
+
: activity;
|
|
277
|
+
}),
|
|
278
|
+
}
|
|
279
|
+
: body;
|
|
280
|
+
wf.template = { ...pinned };
|
|
281
|
+
return { code };
|
|
282
|
+
}
|
|
283
|
+
case "/api/api/workflow/validate":
|
|
284
|
+
case "/api/api/workflow/publish": {
|
|
285
|
+
const code = String(body.workflowCode ?? q.workflowCode ?? "");
|
|
286
|
+
const wf = ctx.state.workflows.get(code);
|
|
287
|
+
if (!wf)
|
|
288
|
+
return null;
|
|
289
|
+
if (body.activities !== undefined && invalidRenderShape(body))
|
|
290
|
+
return businessRefusal(50000, "服务异常");
|
|
291
|
+
// Live 8.6.26 fidelity (2026-09-17): validate/publish REFUSE with HTTP
|
|
292
|
+
// 200 + errcode 0 and the truth in `data` as ValidateMessage[]
|
|
293
|
+
// ({errCode, errContent, errorLevel}). The originate (first PARTICIPANT)
|
|
294
|
+
// node's participant must be the platform keyword "{Originator}" — a
|
|
295
|
+
// plain user/role value answers 401035 ERROR while errcode stays 0, and
|
|
296
|
+
// the flow never goes live. `{Creator}` on a non-originate node is a WARN
|
|
297
|
+
// (401062) that does not block.
|
|
298
|
+
const activities = Array.isArray(body.activities) ? body.activities : wf.template.activities;
|
|
299
|
+
const validation = validateWorkflowParticipants(activities);
|
|
300
|
+
if (input.path === "/api/api/workflow/validate")
|
|
301
|
+
return validation;
|
|
302
|
+
if (validation.some((message) => message.errorLevel === "ERROR"))
|
|
303
|
+
return validation;
|
|
304
|
+
// Ticket 77: the published face carries the PUBLISH marker (live readback
|
|
305
|
+
// evidence: publish state is identified by templateType:PUBLISH /
|
|
306
|
+
// version fields, never by data presence).
|
|
307
|
+
wf.published = { ...body, templateType: "PUBLISH", workflowVersion: (wf.published ? Number(wf.published.workflowVersion ?? 1) : 0) + 1 };
|
|
308
|
+
return { code, workflowVersion: wf.published.workflowVersion };
|
|
309
|
+
}
|
|
310
|
+
case "/api/api/workflow/delete":
|
|
311
|
+
ctx.state.workflows.delete(String(body.workflowCode ?? q.workflowCode ?? q.code ?? ""));
|
|
312
|
+
return null;
|
|
313
|
+
case "/api/api/runtime/workflow/search_workitems": {
|
|
314
|
+
// The real endpoint returns the caller's pending todos (biz_workitem only
|
|
315
|
+
// holds pending rows); finished items move to the finished store. The
|
|
316
|
+
// server's filterWorkflowInstanceId is a NOT-equal exclusion, so it is
|
|
317
|
+
// deliberately not honored here — exact instance matching is client-side.
|
|
318
|
+
let rows = [...ctx.state.workItems.values()].filter((item) => PENDING_STATES.has(item.state));
|
|
319
|
+
if (q.workflowCode)
|
|
320
|
+
rows = rows.filter((item) => item.workflowCode === q.workflowCode);
|
|
321
|
+
if (q.schemaCode)
|
|
322
|
+
rows = rows.filter((item) => item.schemaCode === q.schemaCode);
|
|
323
|
+
const page = Number(q.page ?? 0);
|
|
324
|
+
const size = Number(q.size ?? 20);
|
|
325
|
+
const start = page * size;
|
|
326
|
+
return {
|
|
327
|
+
totalElements: rows.length,
|
|
328
|
+
totalPages: size > 0 ? Math.ceil(rows.length / size) : 0,
|
|
329
|
+
content: rows.slice(start, start + size).map(toWorkItemVO),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
case "/api/api/runtime/workflow/getBizObjectByWfInstanceId": {
|
|
333
|
+
const instanceId = String(q.workflowInstanceId ?? "");
|
|
334
|
+
const item = [...ctx.state.workItems.values()].find((candidate) => candidate.instanceId === instanceId);
|
|
335
|
+
if (!item)
|
|
336
|
+
return null;
|
|
337
|
+
return { id: item.bizObjectId, schemaCode: item.schemaCode };
|
|
338
|
+
}
|
|
339
|
+
case "/api/api/organization/role/list":
|
|
340
|
+
// Real shape: groups with `children` roles (see real-env observation).
|
|
341
|
+
return [
|
|
342
|
+
{ id: "grp-1", name: "默认", code: "SYS_1000000", children: [{ id: "role-lead", name: "部门负责人", code: "SYS260630023816197", roleType: "SYS", corpId: "corp-1" }] },
|
|
343
|
+
{ id: "role-finance", name: "财务负责人", code: "SYS260515031207258", roleType: "SYS", corpId: "corp-1" },
|
|
344
|
+
];
|
|
345
|
+
case "/api/api/organization/department/tree":
|
|
346
|
+
return { departmentList: [{ id: "dept-1", name: "总所", code: "1", corpId: "corp-1", parentId: null }, { id: "dept-2", name: "业务部", code: "1_1", corpId: "corp-1", parentId: "dept-1" }] };
|
|
347
|
+
case "/api/api/organization/user/search": {
|
|
348
|
+
// UserController.search: @RequestBody {wd,page,size} → PageVO<UserVO>.
|
|
349
|
+
const wd = String(body.wd ?? "");
|
|
350
|
+
if (!wd)
|
|
351
|
+
return businessRefusal(10005, "关键字不能为空");
|
|
352
|
+
const users = [
|
|
353
|
+
{ id: "user-1", username: "18900000001", name: "付文彬", departmentId: "dept-1", userId: "18900000001", status: "ENABLE", deleted: false, corpId: "corp-1" },
|
|
354
|
+
{ id: "user-2", username: "18900000002", name: "李四", departmentId: "dept-2", userId: "18900000002", status: "ENABLE", deleted: false, corpId: "corp-1" },
|
|
355
|
+
].filter((user) => user.name.includes(wd) || user.username.includes(wd));
|
|
356
|
+
const page = Number(body.page ?? 0);
|
|
357
|
+
const size = Number(body.size ?? 100);
|
|
358
|
+
return { totalElements: users.length, totalPages: size > 0 ? Math.ceil(users.length / size) : 0, content: users.slice(page * size, page * size + size) };
|
|
359
|
+
}
|
|
360
|
+
default:
|
|
361
|
+
return NOT_HANDLED;
|
|
362
|
+
}
|
|
363
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stalfh233/omc-fake-platform",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.4.39",
|
|
4
|
+
"description": "OMC 的内存假 CloudPivot 平台(wire 接缝的第二个适配器)+ HTTP 假服务器——@stalfh233/omc-cli 的测试与 bench 基准基座",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./state": "./dist/state.js",
|
|
10
|
+
"./http-server": "./dist/http-server.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"package.json",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc --project tsconfig.build.json"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"omc-core": "0.4.39"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22.13"
|
|
25
|
+
}
|
|
26
|
+
}
|