@qfei-design/make-app-approval 0.0.0-stage → 0.1.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/PUBLIC_API.md +129 -0
- package/README.md +65 -2
- package/capabilities.json +76 -0
- package/dist/detail/approval-task-detail.d.ts +2 -0
- package/dist/detail/diagnostics.d.ts +2 -0
- package/dist/detail/field-value.d.ts +2 -0
- package/dist/detail/index.d.ts +3 -0
- package/dist/detail/task-policy.d.ts +18 -0
- package/dist/detail/types.d.ts +111 -0
- package/dist/detail.cjs +1 -0
- package/dist/detail.mjs +500 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.mjs +30 -0
- package/dist/list/approval-table.d.ts +14 -0
- package/dist/list/diagnostics.d.ts +3 -0
- package/dist/list/index.d.ts +3 -0
- package/dist/list/my-approvals-page.d.ts +2 -0
- package/dist/list/page-contract.d.ts +3 -0
- package/dist/list/status-label.d.ts +1 -0
- package/dist/list/types.d.ts +71 -0
- package/dist/list/ui-components.d.ts +44 -0
- package/dist/list/use-approval-page.d.ts +12 -0
- package/dist/list/virtual-page-loader.d.ts +26 -0
- package/dist/list.cjs +1 -0
- package/dist/list.mjs +381 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react.cjs +1 -0
- package/dist/react.mjs +17 -0
- package/dist/styles.css +94 -0
- package/dist/styles.css.d.ts +1 -0
- package/dist/withdrawal.d.ts +14 -0
- package/docs/host-integration.md +217 -0
- package/docs/implementation-plan.md +61 -0
- package/docs/publishing.md +108 -0
- package/examples/antd-components.tsx +38 -0
- package/examples/detail-integration.tsx +80 -0
- package/examples/host-integration.tsx +36 -0
- package/package.ai.json +85 -0
- package/package.json +117 -4
- package/recipes.json +114 -0
package/dist/detail.mjs
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { jsx as n, jsxs as o, Fragment as we } from "react/jsx-runtime";
|
|
2
|
+
import { useState as u, useRef as Q, useEffect as de, useId as Te } from "react";
|
|
3
|
+
import { ApprovalStatus as Ee } from "./react.mjs";
|
|
4
|
+
import { isApprovalSystemField as Ae } from "./index.mjs";
|
|
5
|
+
const N = (e) => !!e && typeof e == "object" && !Array.isArray(e), b = (e) => typeof e == "string" && e.trim().length > 0, Ne = ["APPROVE", "REJECT", "RETURN", "SUBMIT"], $ = (e) => {
|
|
6
|
+
if (e === void 0) return [];
|
|
7
|
+
if (!N(e)) throw new Error("审批字段权限格式无效");
|
|
8
|
+
if (e.scope === "NONE" && e.fields === void 0) return [];
|
|
9
|
+
if (e.scope !== "FIELDS" || !Array.isArray(e.fields) || !e.fields.every(b) || new Set(e.fields).size !== e.fields.length)
|
|
10
|
+
throw new Error("审批字段权限范围无效");
|
|
11
|
+
return e.fields;
|
|
12
|
+
}, Ie = (e) => N(e) && b(e.key) && b(e.label) && (e.required === void 0 || typeof e.required == "boolean") && (e.schema === void 0 || N(e.schema)), Oe = (e) => {
|
|
13
|
+
if (!N(e) || !Ne.some((a) => a === e.actionType) || e.commentPolicy !== "REQUIRED" && e.commentPolicy !== "OPTIONAL")
|
|
14
|
+
return !1;
|
|
15
|
+
const t = e.returnTargets;
|
|
16
|
+
return t === void 0 || Array.isArray(t) && t.every((a) => N(a) && b(a.nodeKey) && b(a.nodeName)) && new Set(t.map((a) => a.nodeKey)).size === t.length;
|
|
17
|
+
}, pe = (e) => {
|
|
18
|
+
if (!N(e) || !b(e.taskId) || !b(e.processInstanceId) || !b(e.taskName) || !b(e.processStatus) || !Array.isArray(e.fields) || !e.fields.every(Ie) || !N(e.formData))
|
|
19
|
+
throw new Error("审批详情数据不完整");
|
|
20
|
+
const t = e.fields.map((i) => i.key);
|
|
21
|
+
if (new Set(t).size !== t.length) throw new Error("审批字段标识重复");
|
|
22
|
+
if (e.fieldPermission !== void 0 && !N(e.fieldPermission))
|
|
23
|
+
throw new Error("审批字段权限格式无效");
|
|
24
|
+
const a = e.fieldPermission, s = $(a?.viewPermission), p = $(a?.editPermission);
|
|
25
|
+
if (s.some((i) => !t.includes(i)) || p.some((i) => !s.includes(i)))
|
|
26
|
+
throw new Error("审批字段元数据或权限不一致");
|
|
27
|
+
const d = e.actions ?? [];
|
|
28
|
+
if (!Array.isArray(d) || !d.every(Oe) || new Set(d.map((i) => i.actionType)).size !== d.length)
|
|
29
|
+
throw new Error("审批操作配置无效");
|
|
30
|
+
return {
|
|
31
|
+
taskId: e.taskId,
|
|
32
|
+
processInstanceId: e.processInstanceId,
|
|
33
|
+
taskName: e.taskName,
|
|
34
|
+
processStatus: e.processStatus,
|
|
35
|
+
fields: e.fields,
|
|
36
|
+
formData: e.formData,
|
|
37
|
+
actions: d,
|
|
38
|
+
fieldPermission: {
|
|
39
|
+
viewPermission: { scope: "FIELDS", fields: s },
|
|
40
|
+
editPermission: { scope: "FIELDS", fields: p }
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}, q = (e) => {
|
|
44
|
+
const t = new Set(
|
|
45
|
+
$(e.fieldPermission?.viewPermission)
|
|
46
|
+
), a = new Set(
|
|
47
|
+
$(e.fieldPermission?.editPermission)
|
|
48
|
+
);
|
|
49
|
+
return e.fields.filter((s) => t.has(s.key)).map((s) => ({
|
|
50
|
+
...s,
|
|
51
|
+
editable: a.has(s.key) && !Ae(s.key)
|
|
52
|
+
}));
|
|
53
|
+
};
|
|
54
|
+
class A extends Error {
|
|
55
|
+
constructor(t, a = {}) {
|
|
56
|
+
super(t), this.fieldErrors = a, this.name = "ApprovalTaskValidationError";
|
|
57
|
+
}
|
|
58
|
+
fieldErrors;
|
|
59
|
+
}
|
|
60
|
+
const G = (e) => e.actionType === "RETURN" || e.actionType === "REJECT" || e.actionType === "SUBMIT" && e.commentPolicy === "REQUIRED", Se = (e, t) => Object.fromEntries(
|
|
61
|
+
e.filter((a) => {
|
|
62
|
+
const s = t[a.key];
|
|
63
|
+
return s == null || typeof s == "string" && !s.trim() || Array.isArray(s) && s.length === 0;
|
|
64
|
+
}).map((a) => [a.key, `请填写${a.label}`])
|
|
65
|
+
), ce = (e, t, a, s, p) => {
|
|
66
|
+
const d = e.actions.find((c) => c.actionType === t);
|
|
67
|
+
if (!d)
|
|
68
|
+
throw new A("当前节点不允许此操作,请刷新详情");
|
|
69
|
+
const i = new Set(
|
|
70
|
+
q(e).filter((c) => c.editable).map((c) => c.key)
|
|
71
|
+
);
|
|
72
|
+
if (Object.keys(a).some((c) => !i.has(c)))
|
|
73
|
+
throw new A("字段权限已变化,请重新加载详情");
|
|
74
|
+
if (G(d) && !s.trim())
|
|
75
|
+
throw new A("请填写审批意见");
|
|
76
|
+
if (s.length > 1024)
|
|
77
|
+
throw new A("审批意见不能超过 1024 个字符");
|
|
78
|
+
if (t === "RETURN" && !d.returnTargets?.some((c) => c.nodeKey === p))
|
|
79
|
+
throw new A("请选择后台配置的退回节点");
|
|
80
|
+
return {
|
|
81
|
+
taskId: e.taskId,
|
|
82
|
+
processInstanceId: e.processInstanceId,
|
|
83
|
+
actionType: t,
|
|
84
|
+
comment: s.trim(),
|
|
85
|
+
recordPatch: { ...a },
|
|
86
|
+
...t === "RETURN" ? { targetNodeKey: p } : {}
|
|
87
|
+
};
|
|
88
|
+
}, f = (e, t) => {
|
|
89
|
+
try {
|
|
90
|
+
e ? e(t) : t.phase === "error" ? console.warn("[make-app-approval]", t) : console.info("[make-app-approval]", t);
|
|
91
|
+
} catch {
|
|
92
|
+
console.warn("[make-app-approval] diagnostic sink failed");
|
|
93
|
+
}
|
|
94
|
+
}, H = (e, t) => {
|
|
95
|
+
if (Object.is(e, t)) return !0;
|
|
96
|
+
if (e instanceof Date && t instanceof Date)
|
|
97
|
+
return Object.is(e.getTime(), t.getTime());
|
|
98
|
+
if (Array.isArray(e) || Array.isArray(t))
|
|
99
|
+
return Array.isArray(e) && Array.isArray(t) && e.length === t.length && e.every((p, d) => H(p, t[d]));
|
|
100
|
+
if (!e || !t || typeof e != "object" || typeof t != "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(e)) || ![Object.prototype, null].includes(Object.getPrototypeOf(t))) return !1;
|
|
101
|
+
const a = e, s = t;
|
|
102
|
+
return Object.keys(a).length === Object.keys(s).length && Object.keys(a).every((p) => Object.hasOwn(s, p) && H(a[p], s[p]));
|
|
103
|
+
}, D = {
|
|
104
|
+
APPROVE: "同意",
|
|
105
|
+
REJECT: "拒绝",
|
|
106
|
+
RETURN: "退回修改",
|
|
107
|
+
SUBMIT: "提交"
|
|
108
|
+
}, W = (e, t) => e.taskId === t.reference.taskId && e.processInstanceId === t.reference.processInstanceId, je = ({
|
|
109
|
+
title: e,
|
|
110
|
+
actions: t,
|
|
111
|
+
content: a,
|
|
112
|
+
footer: s
|
|
113
|
+
}) => /* @__PURE__ */ o("section", { className: "make-app-approval-detail", "aria-label": "审批详情", children: [
|
|
114
|
+
/* @__PURE__ */ o("header", { className: "make-app-approval-detail-header", children: [
|
|
115
|
+
e,
|
|
116
|
+
t
|
|
117
|
+
] }),
|
|
118
|
+
/* @__PURE__ */ n("div", { className: "make-app-approval-detail-content", children: a }),
|
|
119
|
+
s && /* @__PURE__ */ n("footer", { className: "make-app-approval-detail-footer", children: s })
|
|
120
|
+
] }), le = (e) => /* @__PURE__ */ o("div", { className: "make-app-approval-detail-title", children: [
|
|
121
|
+
/* @__PURE__ */ n("h2", { children: "审批详情" }),
|
|
122
|
+
e && /* @__PURE__ */ n(Ee, { value: e })
|
|
123
|
+
] }), Re = (e) => {
|
|
124
|
+
const [t, a] = u(0), [s, p] = u(), d = Q(e);
|
|
125
|
+
d.current = e, de(() => {
|
|
126
|
+
const c = new AbortController(), k = d.current;
|
|
127
|
+
return f(k.logger, { operation: "detail", phase: "start" }), (async () => {
|
|
128
|
+
try {
|
|
129
|
+
const l = pe(
|
|
130
|
+
await k.provider.loadDetail(k.reference, {
|
|
131
|
+
signal: c.signal
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
if (c.signal.aborted) return;
|
|
135
|
+
if (!W(l, k))
|
|
136
|
+
throw new Error("Task identity mismatch");
|
|
137
|
+
p({ revision: t, detail: l }), f(k.logger, { operation: "detail", phase: "success" });
|
|
138
|
+
} catch {
|
|
139
|
+
if (c.signal.aborted) return;
|
|
140
|
+
p({ revision: t, error: !0 }), f(k.logger, { operation: "detail", phase: "error" });
|
|
141
|
+
}
|
|
142
|
+
})(), () => {
|
|
143
|
+
c.abort(), f(k.logger, { operation: "detail", phase: "cancel" });
|
|
144
|
+
};
|
|
145
|
+
}, [t]);
|
|
146
|
+
const i = s?.revision === t ? s : void 0;
|
|
147
|
+
return /* @__PURE__ */ n(
|
|
148
|
+
Pe,
|
|
149
|
+
{
|
|
150
|
+
...e,
|
|
151
|
+
data: i?.detail,
|
|
152
|
+
loadError: i?.error === !0,
|
|
153
|
+
reload: () => a((c) => c + 1)
|
|
154
|
+
},
|
|
155
|
+
t
|
|
156
|
+
);
|
|
157
|
+
}, Pe = (e) => {
|
|
158
|
+
const {
|
|
159
|
+
components: { Button: t, Select: a, TextArea: s },
|
|
160
|
+
renderField: p,
|
|
161
|
+
reload: d
|
|
162
|
+
} = e, i = Te(), [c, k] = u(), l = c ?? e.data, [g, B] = u({}), [U, S] = u(), [L, X] = u(""), [x, C] = u(""), [F, J] = u({}), [Y, v] = u(""), [w, Z] = u(!1), [R, me] = u(!1), [j, ye] = u(!1), K = Q(!1), V = Q(new AbortController());
|
|
163
|
+
de(() => (V.current = new AbortController(), () => V.current.abort()), []);
|
|
164
|
+
const _ = l ? q(l) : [], T = l?.actions.find((r) => r.actionType === U), ee = T ? G(T) : !1, te = l?.actions.filter(G) ?? [], re = w || R || j, ae = e.renderLayout ?? je, he = async () => {
|
|
165
|
+
if (!l || !U || K.current || R || j) return;
|
|
166
|
+
K.current = !0, Z(!0), v(""), J({});
|
|
167
|
+
const r = V.current.signal, y = U;
|
|
168
|
+
let I = !1;
|
|
169
|
+
f(e.logger, {
|
|
170
|
+
operation: "action",
|
|
171
|
+
phase: "start",
|
|
172
|
+
actionType: y
|
|
173
|
+
});
|
|
174
|
+
try {
|
|
175
|
+
ce(l, y, g, L, x);
|
|
176
|
+
const m = pe(
|
|
177
|
+
await e.provider.loadDetail(e.reference, { signal: r })
|
|
178
|
+
);
|
|
179
|
+
if (r.aborted) return;
|
|
180
|
+
if (!W(m, e)) throw new Error("Task identity mismatch");
|
|
181
|
+
const be = q(l), M = q(m);
|
|
182
|
+
if (JSON.stringify(be) !== JSON.stringify(M) || JSON.stringify(l.actions) !== JSON.stringify(m.actions)) {
|
|
183
|
+
k(m), B({}), S(void 0), X(""), C(""), v("当前节点的字段或操作权限已变化,请核对后重新操作"), f(e.logger, {
|
|
184
|
+
operation: "action",
|
|
185
|
+
phase: "skip",
|
|
186
|
+
actionType: y
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const se = M.filter(
|
|
191
|
+
(h) => !H(l.formData[h.key], m.formData[h.key])
|
|
192
|
+
);
|
|
193
|
+
if (se.length) {
|
|
194
|
+
const h = new Set(se.map((O) => O.key)), z = Object.keys(g).some((O) => h.has(O));
|
|
195
|
+
k(m), B(Object.fromEntries(Object.entries(g).filter(([O]) => !h.has(O)))), S(void 0), C(""), v(z ? "申请内容已更新,冲突字段的本地修改已清除,其他修改已保留,请核对后重新操作" : "申请内容已更新,您的修改已保留,请核对后重新操作"), f(e.logger, { operation: "action", phase: "skip", actionType: y });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const P = M.filter(
|
|
199
|
+
(h) => h.editable && h.required === !0
|
|
200
|
+
), oe = Object.fromEntries(
|
|
201
|
+
P.map((h) => [
|
|
202
|
+
h.key,
|
|
203
|
+
Object.hasOwn(g, h.key) ? g[h.key] : m.formData[h.key]
|
|
204
|
+
])
|
|
205
|
+
), ne = Se(
|
|
206
|
+
P,
|
|
207
|
+
oe
|
|
208
|
+
);
|
|
209
|
+
if (Object.keys(ne).length)
|
|
210
|
+
throw new A(
|
|
211
|
+
"请检查表单中标红的字段",
|
|
212
|
+
ne
|
|
213
|
+
);
|
|
214
|
+
const ge = P.length ? await e.validateFields({
|
|
215
|
+
fields: P,
|
|
216
|
+
values: oe,
|
|
217
|
+
actionType: y,
|
|
218
|
+
signal: r
|
|
219
|
+
}) : {};
|
|
220
|
+
if (r.aborted) return;
|
|
221
|
+
const ie = Object.fromEntries(
|
|
222
|
+
Object.entries(ge).filter(
|
|
223
|
+
([h, z]) => P.some((O) => O.key === h) && !!z
|
|
224
|
+
)
|
|
225
|
+
);
|
|
226
|
+
if (Object.keys(ie).length)
|
|
227
|
+
throw new A(
|
|
228
|
+
"请检查表单中标红的字段",
|
|
229
|
+
ie
|
|
230
|
+
);
|
|
231
|
+
const ve = ce(
|
|
232
|
+
m,
|
|
233
|
+
y,
|
|
234
|
+
g,
|
|
235
|
+
L,
|
|
236
|
+
x
|
|
237
|
+
);
|
|
238
|
+
I = !0;
|
|
239
|
+
const E = await e.provider.submitAction(ve, { signal: r });
|
|
240
|
+
if (r.aborted) return;
|
|
241
|
+
if (!E || !W(E, e) || E.actionType !== y || typeof E.processEnded != "boolean" || typeof E.processStatus != "string" || !E.processStatus.trim())
|
|
242
|
+
throw new Error("Action result mismatch");
|
|
243
|
+
ye(!0), S(void 0), k({ ...m, processStatus: E.processStatus }), v("处理成功"), f(e.logger, {
|
|
244
|
+
operation: "action",
|
|
245
|
+
phase: "success",
|
|
246
|
+
actionType: y
|
|
247
|
+
}), f(e.logger, {
|
|
248
|
+
operation: "notify",
|
|
249
|
+
phase: "start",
|
|
250
|
+
actionType: y
|
|
251
|
+
});
|
|
252
|
+
try {
|
|
253
|
+
await e.onActionSuccess(E), f(e.logger, {
|
|
254
|
+
operation: "notify",
|
|
255
|
+
phase: "success",
|
|
256
|
+
actionType: y
|
|
257
|
+
});
|
|
258
|
+
} catch {
|
|
259
|
+
r.aborted || v("处理已成功,但页面刷新未完成,请刷新列表确认"), f(e.logger, {
|
|
260
|
+
operation: "notify",
|
|
261
|
+
phase: "error",
|
|
262
|
+
actionType: y
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
} catch (m) {
|
|
266
|
+
if (r.aborted) return;
|
|
267
|
+
!I && m instanceof A ? (v(m.message), J(m.fieldErrors)) : (me(!0), S(void 0), v(
|
|
268
|
+
I ? "操作结果尚未确认,请重新加载详情核查,勿重复提交" : "审批权限或字段校验暂不可用,请重新加载详情"
|
|
269
|
+
)), f(e.logger, {
|
|
270
|
+
operation: "action",
|
|
271
|
+
phase: "error",
|
|
272
|
+
actionType: y
|
|
273
|
+
});
|
|
274
|
+
} finally {
|
|
275
|
+
K.current = !1, r.aborted ? f(e.logger, {
|
|
276
|
+
operation: "action",
|
|
277
|
+
phase: "cancel",
|
|
278
|
+
actionType: y
|
|
279
|
+
}) : Z(!1);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
if (!l)
|
|
283
|
+
return ae({
|
|
284
|
+
title: le(),
|
|
285
|
+
actions: null,
|
|
286
|
+
footer: null,
|
|
287
|
+
content: e.loadError ? /* @__PURE__ */ o("div", { className: "make-app-approval-detail-section", role: "alert", children: [
|
|
288
|
+
"审批详情加载失败,请重试",
|
|
289
|
+
/* @__PURE__ */ n(t, { htmlType: "button", variant: "default", onClick: d, children: "重新加载详情" })
|
|
290
|
+
] }) : /* @__PURE__ */ n("div", { className: "make-app-approval-detail-section", role: "status", children: "正在加载审批详情…" })
|
|
291
|
+
});
|
|
292
|
+
const fe = !R && !j && l.actions.length > 0 ? /* @__PURE__ */ n("div", { className: "make-app-approval-detail-actions", "aria-label": "审批操作", children: l.actions.map((r) => /* @__PURE__ */ n(
|
|
293
|
+
t,
|
|
294
|
+
{
|
|
295
|
+
htmlType: "button",
|
|
296
|
+
variant: r.actionType === "APPROVE" || r.actionType === "SUBMIT" ? "primary" : "default",
|
|
297
|
+
disabled: w,
|
|
298
|
+
onClick: () => {
|
|
299
|
+
S(r.actionType), C(""), v(""), document.getElementById(`${i}-comment`)?.focus();
|
|
300
|
+
},
|
|
301
|
+
children: D[r.actionType]
|
|
302
|
+
},
|
|
303
|
+
r.actionType
|
|
304
|
+
)) }) : null, ue = /* @__PURE__ */ o("div", { className: "make-app-approval-detail-content", "aria-busy": w, children: [
|
|
305
|
+
/* @__PURE__ */ o(
|
|
306
|
+
"section",
|
|
307
|
+
{
|
|
308
|
+
className: "make-app-approval-detail-section",
|
|
309
|
+
"aria-label": "申请信息",
|
|
310
|
+
children: [
|
|
311
|
+
/* @__PURE__ */ n("h3", { children: "申请信息" }),
|
|
312
|
+
/* @__PURE__ */ o("div", { className: "make-app-approval-detail-fields", children: [
|
|
313
|
+
_.length === 0 && /* @__PURE__ */ n("p", { children: "当前节点未配置可见字段" }),
|
|
314
|
+
_.map((r) => /* @__PURE__ */ o(
|
|
315
|
+
"div",
|
|
316
|
+
{
|
|
317
|
+
className: "make-app-approval-detail-field",
|
|
318
|
+
"data-invalid": !!F[r.key],
|
|
319
|
+
children: [
|
|
320
|
+
/* @__PURE__ */ o("label", { htmlFor: `${i}-${r.key}`, children: [
|
|
321
|
+
r.label,
|
|
322
|
+
r.required ? /* @__PURE__ */ o(
|
|
323
|
+
"span",
|
|
324
|
+
{
|
|
325
|
+
className: "make-app-approval-required",
|
|
326
|
+
"aria-label": "必填",
|
|
327
|
+
children: [
|
|
328
|
+
" ",
|
|
329
|
+
"*"
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
) : null
|
|
333
|
+
] }),
|
|
334
|
+
/* @__PURE__ */ o("div", { className: "make-app-approval-detail-value", children: [
|
|
335
|
+
p({
|
|
336
|
+
field: r,
|
|
337
|
+
id: `${i}-${r.key}`,
|
|
338
|
+
value: Object.hasOwn(g, r.key) ? g[r.key] : l.formData[r.key],
|
|
339
|
+
readOnly: !r.editable,
|
|
340
|
+
disabled: re,
|
|
341
|
+
error: F[r.key],
|
|
342
|
+
...r.editable && !re ? {
|
|
343
|
+
onChange: (y) => {
|
|
344
|
+
B((I) => ({
|
|
345
|
+
...I,
|
|
346
|
+
[r.key]: y
|
|
347
|
+
})), J((I) => {
|
|
348
|
+
const m = { ...I };
|
|
349
|
+
return delete m[r.key], m;
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
} : {}
|
|
353
|
+
}),
|
|
354
|
+
F[r.key] && /* @__PURE__ */ n("p", { role: "alert", className: "make-app-approval-detail-error", children: F[r.key] })
|
|
355
|
+
] })
|
|
356
|
+
]
|
|
357
|
+
},
|
|
358
|
+
r.key
|
|
359
|
+
))
|
|
360
|
+
] })
|
|
361
|
+
]
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
e.history != null && /* @__PURE__ */ o(
|
|
365
|
+
"section",
|
|
366
|
+
{
|
|
367
|
+
className: "make-app-approval-detail-section make-app-approval-detail-history",
|
|
368
|
+
"aria-label": "审批流程",
|
|
369
|
+
children: [
|
|
370
|
+
/* @__PURE__ */ n("h3", { children: "审批流程" }),
|
|
371
|
+
e.history
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
),
|
|
375
|
+
Y && /* @__PURE__ */ n(
|
|
376
|
+
"p",
|
|
377
|
+
{
|
|
378
|
+
role: j ? "status" : "alert",
|
|
379
|
+
className: `make-app-approval-detail-message${j ? "" : " make-app-approval-detail-error"}`,
|
|
380
|
+
children: Y
|
|
381
|
+
}
|
|
382
|
+
),
|
|
383
|
+
R && /* @__PURE__ */ n("div", { className: "make-app-approval-detail-message", children: /* @__PURE__ */ n(t, { htmlType: "button", variant: "default", onClick: d, children: "重新加载详情" }) })
|
|
384
|
+
] }), ke = !R && !j && l.actions.length > 0 ? /* @__PURE__ */ o("div", { className: "make-app-approval-detail-section make-app-approval-detail-opinion", children: [
|
|
385
|
+
/* @__PURE__ */ o("label", { htmlFor: `${i}-comment`, children: [
|
|
386
|
+
"审批意见",
|
|
387
|
+
ee && /* @__PURE__ */ o("span", { className: "make-app-approval-required", "aria-label": "必填", children: [
|
|
388
|
+
" ",
|
|
389
|
+
"*"
|
|
390
|
+
] })
|
|
391
|
+
] }),
|
|
392
|
+
/* @__PURE__ */ n(
|
|
393
|
+
s,
|
|
394
|
+
{
|
|
395
|
+
id: `${i}-comment`,
|
|
396
|
+
ariaLabel: "审批意见",
|
|
397
|
+
value: L,
|
|
398
|
+
onChange: X,
|
|
399
|
+
placeholder: te.length ? `请输入审批意见,${te.map((r) => D[r.actionType]).join("、")}时必填` : "请输入审批意见",
|
|
400
|
+
disabled: w,
|
|
401
|
+
required: ee,
|
|
402
|
+
maxLength: 1024
|
|
403
|
+
}
|
|
404
|
+
),
|
|
405
|
+
T && /* @__PURE__ */ o(
|
|
406
|
+
"section",
|
|
407
|
+
{
|
|
408
|
+
className: "make-app-approval-action-confirm",
|
|
409
|
+
"aria-label": `确认${D[T.actionType]}`,
|
|
410
|
+
children: [
|
|
411
|
+
/* @__PURE__ */ o("h3", { children: [
|
|
412
|
+
"确认",
|
|
413
|
+
D[T.actionType]
|
|
414
|
+
] }),
|
|
415
|
+
T.actionType === "RETURN" && /* @__PURE__ */ o("div", { className: "make-app-approval-detail-target", children: [
|
|
416
|
+
/* @__PURE__ */ n("label", { htmlFor: `${i}-target`, children: "退回节点" }),
|
|
417
|
+
/* @__PURE__ */ n(
|
|
418
|
+
a,
|
|
419
|
+
{
|
|
420
|
+
id: `${i}-target`,
|
|
421
|
+
ariaLabel: "退回节点",
|
|
422
|
+
value: x,
|
|
423
|
+
onChange: C,
|
|
424
|
+
disabled: w,
|
|
425
|
+
options: [
|
|
426
|
+
{ value: "", label: "请选择退回节点" },
|
|
427
|
+
...(T.returnTargets ?? []).map((r) => ({
|
|
428
|
+
value: r.nodeKey,
|
|
429
|
+
label: r.nodeName
|
|
430
|
+
}))
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
)
|
|
434
|
+
] }),
|
|
435
|
+
/* @__PURE__ */ o("div", { className: "make-app-approval-detail-actions", children: [
|
|
436
|
+
/* @__PURE__ */ o(
|
|
437
|
+
t,
|
|
438
|
+
{
|
|
439
|
+
htmlType: "button",
|
|
440
|
+
variant: "primary",
|
|
441
|
+
disabled: w,
|
|
442
|
+
loading: w,
|
|
443
|
+
onClick: () => {
|
|
444
|
+
he();
|
|
445
|
+
},
|
|
446
|
+
children: [
|
|
447
|
+
"确认",
|
|
448
|
+
D[T.actionType]
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
/* @__PURE__ */ n(
|
|
453
|
+
t,
|
|
454
|
+
{
|
|
455
|
+
htmlType: "button",
|
|
456
|
+
variant: "default",
|
|
457
|
+
disabled: w,
|
|
458
|
+
onClick: () => S(void 0),
|
|
459
|
+
children: "取消"
|
|
460
|
+
}
|
|
461
|
+
)
|
|
462
|
+
] })
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
)
|
|
466
|
+
] }) : null;
|
|
467
|
+
return ae({
|
|
468
|
+
title: le(l.processStatus),
|
|
469
|
+
actions: fe,
|
|
470
|
+
content: /* @__PURE__ */ o(we, { children: [
|
|
471
|
+
ue,
|
|
472
|
+
ke
|
|
473
|
+
] }),
|
|
474
|
+
footer: null
|
|
475
|
+
});
|
|
476
|
+
}, $e = (e) => {
|
|
477
|
+
if (!e.scopeKey.trim() || !e.reference.taskId.trim() || !e.reference.processInstanceId.trim())
|
|
478
|
+
throw new Error("ApprovalTaskDetail requires scopeKey and task reference");
|
|
479
|
+
for (const t of ["Button", "Select", "TextArea"])
|
|
480
|
+
if (!e.components?.[t])
|
|
481
|
+
throw new Error(`ApprovalTaskDetail requires components.${t}`);
|
|
482
|
+
return /* @__PURE__ */ n(
|
|
483
|
+
Re,
|
|
484
|
+
{
|
|
485
|
+
...e
|
|
486
|
+
},
|
|
487
|
+
JSON.stringify([
|
|
488
|
+
e.scopeKey,
|
|
489
|
+
e.reference.processInstanceId,
|
|
490
|
+
e.reference.taskId
|
|
491
|
+
])
|
|
492
|
+
);
|
|
493
|
+
};
|
|
494
|
+
export {
|
|
495
|
+
$e as ApprovalTaskDetail,
|
|
496
|
+
A as ApprovalTaskValidationError,
|
|
497
|
+
ce as buildApprovalTaskAction,
|
|
498
|
+
q as getApprovalTaskFields,
|
|
499
|
+
pe as readApprovalTaskDetail
|
|
500
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=1024,p=e=>{if(typeof e!="string"||!e.trim())return"请填写撤回意见";if(e.trim().length>s)return`撤回意见不能超过 ${s} 个字符`},i="qfei_process_instance_status",l="qfei_is_locked",r={UNSUBMITTED:{label:"—",tone:"neutral"},IN_APPROVAL:{label:"审批中",tone:"processing"},RETURNING:{label:"审批中",tone:"processing"},APPROVED:{label:"已同意",tone:"success"},REJECTED:{label:"已拒绝",tone:"danger"},CANCELLED:{label:"已撤回",tone:"neutral"}},A=e=>e==null?r.UNSUBMITTED:typeof e=="string"&&Object.hasOwn(r,e)?r[e]:{label:"状态未知",tone:"unknown"},c=e=>!!e?.bpmDefinitionKey?.trim(),u=e=>e===i||e===l,t={locked:{reason:"locked",message:"该数据正在审批中,已被锁定,暂不可编辑"},"in-progress":{reason:"in-progress",message:"该数据正在审批中,暂不可编辑"},ended:{reason:"ended",message:"流程已结束,原单只读"},unknown:{reason:"unknown",message:"审批状态暂不可确认,请刷新后重试"}},E=(e,a={})=>{const n=e[i],o=e[l];return o===!0?t.locked:n==="IN_APPROVAL"||n==="RETURNING"?t["in-progress"]:n==="APPROVED"||n==="REJECTED"?t.ended:o!==void 0&&typeof o!="boolean"?t.unknown:n==="UNSUBMITTED"?o===!1?null:t.unknown:n!==void 0||a.approvalEnabled?t.unknown:null};exports.APPROVAL_LOCK_FIELD=l;exports.APPROVAL_STATUS_FIELD=i;exports.APPROVAL_WITHDRAW_COMMENT_MAX_LENGTH=s;exports.getApprovalStatusDisplay=A;exports.getApprovalWithdrawalCommentError=p;exports.getRecordApprovalWriteRestriction=E;exports.hasApprovalDefinition=c;exports.isApprovalSystemField=u;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const APPROVAL_STATUS_FIELD = "qfei_process_instance_status";
|
|
2
|
+
export declare const APPROVAL_LOCK_FIELD = "qfei_is_locked";
|
|
3
|
+
export type ApprovalProcessStatus = "UNSUBMITTED" | "IN_APPROVAL" | "RETURNING" | "APPROVED" | "REJECTED" | "CANCELLED";
|
|
4
|
+
export type ApprovalStatusDisplay = Readonly<{
|
|
5
|
+
label: string;
|
|
6
|
+
tone: "neutral" | "processing" | "success" | "danger" | "unknown";
|
|
7
|
+
}>;
|
|
8
|
+
export declare const getApprovalStatusDisplay: (value: unknown) => ApprovalStatusDisplay;
|
|
9
|
+
export declare const hasApprovalDefinition: (entity: {
|
|
10
|
+
bpmDefinitionKey?: string;
|
|
11
|
+
} | null | undefined) => boolean;
|
|
12
|
+
export declare const isApprovalSystemField: (key: string) => boolean;
|
|
13
|
+
export type ApprovalWriteRestriction = Readonly<{
|
|
14
|
+
reason: "locked" | "in-progress" | "ended" | "unknown";
|
|
15
|
+
message: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** Only guards ordinary record writes. Task actions and list membership are server-owned. */
|
|
18
|
+
export declare const getRecordApprovalWriteRestriction: (record: Readonly<Record<string, unknown>>, options?: {
|
|
19
|
+
approvalEnabled?: boolean;
|
|
20
|
+
}) => ApprovalWriteRestriction | null;
|
|
21
|
+
export * from "./withdrawal.js";
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const a = 1024, A = (n) => {
|
|
2
|
+
if (typeof n != "string" || !n.trim()) return "请填写撤回意见";
|
|
3
|
+
if (n.trim().length > 1024)
|
|
4
|
+
return "撤回意见不能超过 1024 个字符";
|
|
5
|
+
}, r = "qfei_process_instance_status", i = "qfei_is_locked", s = {
|
|
6
|
+
UNSUBMITTED: { label: "—", tone: "neutral" },
|
|
7
|
+
IN_APPROVAL: { label: "审批中", tone: "processing" },
|
|
8
|
+
RETURNING: { label: "审批中", tone: "processing" },
|
|
9
|
+
APPROVED: { label: "已同意", tone: "success" },
|
|
10
|
+
REJECTED: { label: "已拒绝", tone: "danger" },
|
|
11
|
+
CANCELLED: { label: "已撤回", tone: "neutral" }
|
|
12
|
+
}, c = (n) => n == null ? s.UNSUBMITTED : typeof n == "string" && Object.hasOwn(s, n) ? s[n] : { label: "状态未知", tone: "unknown" }, p = (n) => !!n?.bpmDefinitionKey?.trim(), E = (n) => n === r || n === i, t = {
|
|
13
|
+
locked: { reason: "locked", message: "该数据正在审批中,已被锁定,暂不可编辑" },
|
|
14
|
+
"in-progress": { reason: "in-progress", message: "该数据正在审批中,暂不可编辑" },
|
|
15
|
+
ended: { reason: "ended", message: "流程已结束,原单只读" },
|
|
16
|
+
unknown: { reason: "unknown", message: "审批状态暂不可确认,请刷新后重试" }
|
|
17
|
+
}, u = (n, l = {}) => {
|
|
18
|
+
const e = n[r], o = n[i];
|
|
19
|
+
return o === !0 ? t.locked : e === "IN_APPROVAL" || e === "RETURNING" ? t["in-progress"] : e === "APPROVED" || e === "REJECTED" ? t.ended : o !== void 0 && typeof o != "boolean" ? t.unknown : e === "UNSUBMITTED" ? o === !1 ? null : t.unknown : e !== void 0 || l.approvalEnabled ? t.unknown : null;
|
|
20
|
+
};
|
|
21
|
+
export {
|
|
22
|
+
i as APPROVAL_LOCK_FIELD,
|
|
23
|
+
r as APPROVAL_STATUS_FIELD,
|
|
24
|
+
a as APPROVAL_WITHDRAW_COMMENT_MAX_LENGTH,
|
|
25
|
+
c as getApprovalStatusDisplay,
|
|
26
|
+
A as getApprovalWithdrawalCommentError,
|
|
27
|
+
u as getRecordApprovalWriteRestriction,
|
|
28
|
+
p as hasApprovalDefinition,
|
|
29
|
+
E as isApprovalSystemField
|
|
30
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApprovalListItem, ApprovalListQuery, ApprovalListProvider, ApprovalPage, ApprovalLogger } from "./types.js";
|
|
2
|
+
import type { ApprovalUIComponents } from "./ui-components.js";
|
|
3
|
+
type Props = {
|
|
4
|
+
components: ApprovalUIComponents;
|
|
5
|
+
initialPage?: ApprovalPage;
|
|
6
|
+
query: ApprovalListQuery;
|
|
7
|
+
provider: ApprovalListProvider;
|
|
8
|
+
themeKey?: string | number;
|
|
9
|
+
onOpen: (item: ApprovalListItem) => void;
|
|
10
|
+
onReload: () => void;
|
|
11
|
+
logger?: ApprovalLogger;
|
|
12
|
+
};
|
|
13
|
+
export declare const ApprovalTable: (props: Props) => import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { MyApprovalsPage } from "./my-approvals-page.js";
|
|
2
|
+
export type { ApprovalUIComponents, ApprovalInputProps, ApprovalSelectProps, ApprovalDatePickerProps, ApprovalButtonProps, ApprovalTabsProps, } from "./ui-components.js";
|
|
3
|
+
export type { ApprovalListTab, ApprovalListItem, ApprovalListFilters, ApprovalListQuery, ApprovalPage, ApprovalListProvider, ApprovalStatusOption, ApprovalDiagnostic, ApprovalLogger, MyApprovalsPageProps, } from "./types.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getApprovalListStatusLabel: (value: unknown) => string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ApprovalUIComponents } from "./ui-components.js";
|
|
2
|
+
/** 包与宿主之间的数据约定,不是 BPM 后端接口 DTO。 */
|
|
3
|
+
export type ApprovalListTab = "pending" | "approved";
|
|
4
|
+
export type ApprovalListItem = Readonly<{
|
|
5
|
+
/** 后端提供的稳定列表行标识,不使用申请单号或数组下标。 */
|
|
6
|
+
id: string;
|
|
7
|
+
entityKey: string;
|
|
8
|
+
recordId: string;
|
|
9
|
+
taskId?: string;
|
|
10
|
+
processInstanceId?: string;
|
|
11
|
+
applicationNo: string;
|
|
12
|
+
applicationType: string;
|
|
13
|
+
applicantName: string;
|
|
14
|
+
/** 宿主按应用时区格式化后的展示文字。 */
|
|
15
|
+
applicationTime: string;
|
|
16
|
+
processStatus: string | null;
|
|
17
|
+
}>;
|
|
18
|
+
export type ApprovalListFilters = Readonly<{
|
|
19
|
+
keyword: string;
|
|
20
|
+
processStatus: string;
|
|
21
|
+
/** YYYY-MM-DD,空字符串表示不限;时区与边界转换由 Service 处理。 */
|
|
22
|
+
startDate: string;
|
|
23
|
+
endDate: string;
|
|
24
|
+
}>;
|
|
25
|
+
export type ApprovalListQuery = ApprovalListFilters & Readonly<{
|
|
26
|
+
tab: ApprovalListTab;
|
|
27
|
+
/** 从 1 开始。 */
|
|
28
|
+
page: number;
|
|
29
|
+
pageSize: number;
|
|
30
|
+
}>;
|
|
31
|
+
export type ApprovalPage = Readonly<{
|
|
32
|
+
rows: readonly ApprovalListItem[];
|
|
33
|
+
/** 后端完成当前用户、页签和筛选后计算的总数。 */
|
|
34
|
+
total: number;
|
|
35
|
+
}>;
|
|
36
|
+
export type ApprovalListProvider = Readonly<{
|
|
37
|
+
loadPage: (query: ApprovalListQuery, context: Readonly<{
|
|
38
|
+
signal: AbortSignal;
|
|
39
|
+
}>) => Promise<ApprovalPage>;
|
|
40
|
+
}>;
|
|
41
|
+
export type ApprovalStatusOption = Readonly<{
|
|
42
|
+
value: string;
|
|
43
|
+
label: string;
|
|
44
|
+
}>;
|
|
45
|
+
export type ApprovalDiagnostic = Readonly<{
|
|
46
|
+
operation: "list" | "table" | "open";
|
|
47
|
+
phase: "start" | "success" | "error" | "cancel" | "skip" | "destroy";
|
|
48
|
+
tab?: ApprovalListTab;
|
|
49
|
+
page?: number;
|
|
50
|
+
pageSize?: number;
|
|
51
|
+
rowCount?: number;
|
|
52
|
+
}>;
|
|
53
|
+
export type ApprovalLogger = (event: ApprovalDiagnostic) => void;
|
|
54
|
+
export type MyApprovalsPageProps = Readonly<{
|
|
55
|
+
/** 应用、用户、环境任一变化都必须改变;变化后清空旧数据和筛选。 */
|
|
56
|
+
scopeKey: string;
|
|
57
|
+
/** 宿主组件与主题;包只控制功能和布局,不提供原生控件兜底。 */
|
|
58
|
+
components: ApprovalUIComponents;
|
|
59
|
+
provider: ApprovalListProvider;
|
|
60
|
+
onOpenApproval: (item: ApprovalListItem) => void | Promise<void>;
|
|
61
|
+
/** 后端实际支持的筛选项,未传时只提供“全部流程状态”。 */
|
|
62
|
+
statusOptions?: readonly ApprovalStatusOption[];
|
|
63
|
+
/** 每批加载条数,不是页面翻页控件。默认 20。 */
|
|
64
|
+
pageSize?: number;
|
|
65
|
+
/** 办理成功后改变,触发当前条件重新查询。关闭详情无需改变。 */
|
|
66
|
+
refreshKey?: string | number;
|
|
67
|
+
/** 动态切换主题后改变,重新读取宿主 CSS 变量。 */
|
|
68
|
+
themeKey?: string | number;
|
|
69
|
+
logger?: ApprovalLogger;
|
|
70
|
+
className?: string;
|
|
71
|
+
}>;
|