weaver-e9-assistant-cli 1.0.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/args.js +36 -0
- package/dist/auth-token.js +690 -0
- package/dist/auth.js +187 -0
- package/dist/blog.js +469 -0
- package/dist/cli.js +4041 -0
- package/dist/client.js +199 -0
- package/dist/config.js +124 -0
- package/dist/createcontext.js +41 -0
- package/dist/crypto.js +139 -0
- package/dist/cube.js +1633 -0
- package/dist/email.js +838 -0
- package/dist/fileutil.js +20 -0
- package/dist/kq.js +204 -0
- package/dist/links.js +34 -0
- package/dist/odoc.js +194 -0
- package/dist/pageopen.js +29 -0
- package/dist/parse.js +159 -0
- package/dist/querystate.js +38 -0
- package/dist/render.js +21 -0
- package/dist/report.js +50 -0
- package/dist/submissionplan.js +43 -0
- package/dist/submissionstate.js +81 -0
- package/dist/todoaskidea.js +54 -0
- package/dist/todobatch.js +154 -0
- package/dist/todocc.js +128 -0
- package/dist/todoforward.js +66 -0
- package/dist/todoreject.js +215 -0
- package/dist/todosubmit.js +277 -0
- package/dist/todotransfer.js +54 -0
- package/dist/util.js +25 -0
- package/dist/wfcreate.js +102 -0
- package/dist/wfform.js +194 -0
- package/dist/wfops.js +40 -0
- package/dist/wfreceiver.js +43 -0
- package/dist/wfstart.js +717 -0
- package/dist/wfsummary.js +89 -0
- package/dist/wfupload.js +78 -0
- package/dist/wfuser.js +60 -0
- package/dist/workflow.js +461 -0
- package/dist/workplan.js +394 -0
- package/package.json +25 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createApiFromProfile } from './client.js';
|
|
2
|
+
export async function getFlowSummary(cfg, requestId) {
|
|
3
|
+
const api = await createApiFromProfile(cfg);
|
|
4
|
+
// 第一步 loadForm(不带 wf+node)→ 拿 workflowid/nodeid
|
|
5
|
+
const r0 = await api.post('/api/workflow/reqform/loadForm', { iscreate: '0', requestid: requestId });
|
|
6
|
+
const j0 = r0.json ?? {};
|
|
7
|
+
const wfId = String(j0.params?.workflowid ?? '');
|
|
8
|
+
const nodeId = String(j0.params?.nodeid ?? '');
|
|
9
|
+
// 第二步 loadForm(带 wf+node)→ 拿 per-request 签名(不带则签名字段空)
|
|
10
|
+
let j = j0;
|
|
11
|
+
if (wfId && nodeId) {
|
|
12
|
+
const r1 = await api.post('/api/workflow/reqform/loadForm', { iscreate: '0', requestid: requestId, workflowid: wfId, nodeid: nodeId });
|
|
13
|
+
j = r1.json ?? j0;
|
|
14
|
+
}
|
|
15
|
+
const fm = j.tableInfo?.main?.fieldinfomap ?? {};
|
|
16
|
+
const md = j.maindata ?? {};
|
|
17
|
+
const fields = Object.entries(fm).map(([id, f]) => ({
|
|
18
|
+
id,
|
|
19
|
+
label: f?.fieldlabel,
|
|
20
|
+
name: f?.fieldname,
|
|
21
|
+
htmltypeLabel: htmltypeLabel(f?.htmltype),
|
|
22
|
+
value: md[`field${id}`]?.value != null ? String(md[`field${id}`].value) : undefined,
|
|
23
|
+
})).filter((f) => f.value);
|
|
24
|
+
// 流转日志:先调 getRequestLogBaseInfo 取真实的 viewLogIds/creatorNodeId
|
|
25
|
+
const p = j.params ?? {};
|
|
26
|
+
const userId = String(p.f_weaver_belongto_userid ?? '1');
|
|
27
|
+
const sigStr = String(p.signatureAttributesStr ?? '');
|
|
28
|
+
const sigKey = String(p.signatureSecretKey ?? '');
|
|
29
|
+
const commonLogParams = {
|
|
30
|
+
requestid: requestId,
|
|
31
|
+
requestType: '0',
|
|
32
|
+
workflowid: String(p.workflowid ?? ''),
|
|
33
|
+
nodeid: String(p.nodeid ?? ''),
|
|
34
|
+
signatureAttributesStr: sigStr,
|
|
35
|
+
signatureSecretKey: sigKey,
|
|
36
|
+
'f_weaver_belongto_userid': userId,
|
|
37
|
+
'f_weaver_belongto_usertype': String(p.f_weaver_belongto_usertype ?? '0'),
|
|
38
|
+
authStr: String(p.authStr ?? ''),
|
|
39
|
+
authSignatureStr: String(p.authSignatureStr ?? ''),
|
|
40
|
+
wfTestStr: '',
|
|
41
|
+
};
|
|
42
|
+
let logs = [];
|
|
43
|
+
let logDebug = { viewLogIds: '', creatorNodeId: '', source: 'none' };
|
|
44
|
+
try {
|
|
45
|
+
// ① getRequestLogBaseInfo
|
|
46
|
+
let viewLogIds = '';
|
|
47
|
+
let creatorNodeId = '';
|
|
48
|
+
const rBase = await api.post('/api/workflow/reqform/getRequestLogBaseInfo', { ...commonLogParams });
|
|
49
|
+
const baseText = rBase.text ?? '';
|
|
50
|
+
const vlm = baseText.match(/["']?viewLogIds["']?\s*[:=]\s*["']?(\d+(?:%2C|,)?(?:\d+(?:%2C|,)?)*)["']?/i);
|
|
51
|
+
const cnm = baseText.match(/["']?creatorNodeId["']?\s*[:=]\s*["']?(\d+)["']?/i);
|
|
52
|
+
if (vlm)
|
|
53
|
+
viewLogIds = vlm[1].replace(/%2C/gi, ',');
|
|
54
|
+
if (cnm)
|
|
55
|
+
creatorNodeId = cnm[1];
|
|
56
|
+
if (!viewLogIds && p.viewLogIds)
|
|
57
|
+
viewLogIds = String(p.viewLogIds);
|
|
58
|
+
if (!creatorNodeId && p.creatorNodeId)
|
|
59
|
+
creatorNodeId = String(p.creatorNodeId);
|
|
60
|
+
logDebug = { viewLogIds, creatorNodeId, source: (viewLogIds || creatorNodeId) ? 'getRequestLogBaseInfo' : 'none' };
|
|
61
|
+
const rl = await api.post('/api/workflow/reqform/getRequestLogList', {
|
|
62
|
+
...commonLogParams,
|
|
63
|
+
isFromWfForm: '1',
|
|
64
|
+
isprint: '0', isurger: 'false', submit: '0', pgnumber: '1',
|
|
65
|
+
maxrequestlogid: '', viewLogIds, creatorNodeId,
|
|
66
|
+
isHideInput: '', isFormSignature: '', wfsignlddtcnt: '10', orderbytype: '1',
|
|
67
|
+
logpagesize: '', loadmethod: 'split', operatorid: '', deptid: '', subcomid: '',
|
|
68
|
+
content: '', nodename: '', createdateselect: '0', createdatefrom: '', createdateto: '',
|
|
69
|
+
fromCommunication: '', __random__: String(Date.now()),
|
|
70
|
+
});
|
|
71
|
+
logs = rl.json?.loglist ?? [];
|
|
72
|
+
}
|
|
73
|
+
catch { /* 日志取失败不阻断 */ }
|
|
74
|
+
return {
|
|
75
|
+
requestId,
|
|
76
|
+
workflowName: j.cellInfo?.sysFieldInfo?.workflowname,
|
|
77
|
+
workflowId: String(j.params?.workflowid ?? ''),
|
|
78
|
+
nodeId: String(j.params?.nodeid ?? ''),
|
|
79
|
+
verifyRight: j.params?.verifyRight === true,
|
|
80
|
+
fields,
|
|
81
|
+
logs,
|
|
82
|
+
logDebug,
|
|
83
|
+
raw: j,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function htmltypeLabel(ht) {
|
|
87
|
+
const m = { 1: '文本', 2: '多行文本', 3: '浏览选择', 4: '附件', 5: '选择框', 6: '复选框' };
|
|
88
|
+
return m[ht] ?? `ht=${ht}`;
|
|
89
|
+
}
|
package/dist/wfupload.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E9 表单文件上传(图片/附件)。
|
|
3
|
+
*
|
|
4
|
+
* 接口(用户抓包确认):POST /api/doc/upload/uploadFile2Doc
|
|
5
|
+
* query: category=,,<cat>&workflowid=<wf>&listType=<img|list>&uploadSrc=wfform&loginuserid=<uid>
|
|
6
|
+
* multipart: name=<filename>, isFirstUploadFile=9, fieldId=<表单字段id>,
|
|
7
|
+
* workflowId=<wf>, secretLevel=<>, ts=<时间戳>, file=<二进制>
|
|
8
|
+
* listType=img→图片字段;listType=list→附件字段。
|
|
9
|
+
* aiAgentToken 鉴权可用。
|
|
10
|
+
* 响应:data.imagefileid(上传后文件 id,填进表单字段的值)、filename、filelink、versionId、fileidCode 等。
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
const IMG_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'tif', 'tiff']);
|
|
15
|
+
/** 判断文件按图片还是附件上传(按扩展名;可被 --list-type 覆盖)。 */
|
|
16
|
+
export function guessListType(filePath) {
|
|
17
|
+
const ext = (path.extname(filePath).slice(1) || '').toLowerCase();
|
|
18
|
+
return IMG_EXT.has(ext) ? 'img' : 'list';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 上传本地文件到表单字段。返回 imagefileid(填进 field<id> 的值)。
|
|
22
|
+
* listType: 'img'(图片字段) / 'list'(附件字段),不传按扩展名猜。
|
|
23
|
+
*/
|
|
24
|
+
export async function uploadFile(cfg, opts) {
|
|
25
|
+
const { workflowId, fieldId, filePath } = opts;
|
|
26
|
+
const listType = opts.listType ?? guessListType(filePath);
|
|
27
|
+
const category = opts.category ?? '21';
|
|
28
|
+
const loginuserid = opts.loginuserid ?? '1';
|
|
29
|
+
if (!fs.existsSync(filePath))
|
|
30
|
+
throw new Error(`文件不存在: ${filePath}`);
|
|
31
|
+
const buf = fs.readFileSync(filePath);
|
|
32
|
+
const filename = path.basename(filePath);
|
|
33
|
+
const ext = (path.extname(filename).slice(1) || '').toLowerCase();
|
|
34
|
+
const mime = ext === 'png' ? 'image/png'
|
|
35
|
+
: ext === 'jpg' || ext === 'jpeg' ? 'image/jpeg'
|
|
36
|
+
: ext === 'gif' ? 'image/gif'
|
|
37
|
+
: 'application/octet-stream';
|
|
38
|
+
// 直接用 fetch + aiAgentToken(不走 E9Api,因 multipart 需自定义 body)
|
|
39
|
+
const sess = (await import('./auth-token.js')).AuthTokenSession.fromProfile(cfg);
|
|
40
|
+
const base = cfg.baseUrl.replace(/\/+$/, '');
|
|
41
|
+
const url = `${base}/api/doc/upload/uploadFile2Doc?category=,,${category}&workflowid=${workflowId}&listType=${listType}&wfTestStr=&uploadSrc=wfform&loginuserid=${loginuserid}`;
|
|
42
|
+
const fd = new FormData();
|
|
43
|
+
fd.append('name', filename);
|
|
44
|
+
fd.append('isFirstUploadFile', '9');
|
|
45
|
+
fd.append('fieldId', fieldId);
|
|
46
|
+
fd.append('workflowId', String(workflowId));
|
|
47
|
+
fd.append('secretLevel', '');
|
|
48
|
+
fd.append('ts', String(Date.now()));
|
|
49
|
+
fd.append('file', new Blob([buf], { type: mime }), filename);
|
|
50
|
+
const r = await fetch(url, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: { aiAgentToken: sess.token },
|
|
53
|
+
body: fd,
|
|
54
|
+
signal: AbortSignal.timeout(60000),
|
|
55
|
+
});
|
|
56
|
+
const t = await r.text();
|
|
57
|
+
let j = null;
|
|
58
|
+
try {
|
|
59
|
+
j = JSON.parse(t);
|
|
60
|
+
}
|
|
61
|
+
catch { /* non-json */ }
|
|
62
|
+
if (!r.ok || !j?.data?.fileid) {
|
|
63
|
+
throw new Error(`上传失败 status=${r.status}: ${t.slice(0, 300)}`);
|
|
64
|
+
}
|
|
65
|
+
const d = j.data;
|
|
66
|
+
return {
|
|
67
|
+
fileid: String(d.fileid),
|
|
68
|
+
imagefileid: String(d.imagefileid ?? ''),
|
|
69
|
+
filename: d.filename,
|
|
70
|
+
filelink: d.filelink,
|
|
71
|
+
loadlink: d.loadlink,
|
|
72
|
+
versionId: d.versionId,
|
|
73
|
+
fileidCode: d.fileidCode,
|
|
74
|
+
isImg: d.isImg,
|
|
75
|
+
filesize: d.filesize,
|
|
76
|
+
raw: j,
|
|
77
|
+
};
|
|
78
|
+
}
|
package/dist/wfuser.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 当前用户信息(发起流程时,申请人/部门等字段默认填值用)。
|
|
3
|
+
*
|
|
4
|
+
* 接口(用户抓包确认):GET /api/hrm/login/getAccountList?__random__=<ts>
|
|
5
|
+
* aiAgentToken 鉴权。返回 data.{userid, username, deptid, deptname, subcompanyname, jobs}。
|
|
6
|
+
*/
|
|
7
|
+
import { AuthTokenSession } from './auth-token.js';
|
|
8
|
+
import { todayStr } from './util.js';
|
|
9
|
+
/** 取当前登录用户信息。 */
|
|
10
|
+
export async function getCurrentUser(cfg) {
|
|
11
|
+
const sess = AuthTokenSession.fromProfile(cfg);
|
|
12
|
+
const base = cfg.baseUrl.replace(/\/+$/, '');
|
|
13
|
+
const r = await fetch(`${base}/api/hrm/login/getAccountList?__random__=${Date.now()}`, {
|
|
14
|
+
headers: { aiAgentToken: sess.token, 'X-Requested-With': 'XMLHttpRequest' },
|
|
15
|
+
signal: AbortSignal.timeout(12000),
|
|
16
|
+
});
|
|
17
|
+
const j = await r.json();
|
|
18
|
+
const d = j?.data ?? {};
|
|
19
|
+
// accountlist 里 iscurrent=1 的是当前账号;data 顶层也有当前用户字段
|
|
20
|
+
const list = Array.isArray(d.accountlist) ? d.accountlist : [];
|
|
21
|
+
const cur = list.find((a) => String(a.iscurrent) === '1') ?? list[0] ?? d;
|
|
22
|
+
return {
|
|
23
|
+
userid: String(cur.userid ?? ''),
|
|
24
|
+
username: String(cur.username ?? ''),
|
|
25
|
+
deptid: String(cur.deptid ?? ''),
|
|
26
|
+
deptname: String(cur.deptname ?? ''),
|
|
27
|
+
subcompanyname: String(cur.subcompanyname ?? ''),
|
|
28
|
+
jobs: String(cur.jobs ?? ''),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// 人员类标签(→ userid 或 username)
|
|
32
|
+
const PERSON_LABEL = /申请人|发起人|续签人|经办人|经手人|创建人|人员|姓名|联系人|负责人|填报人/;
|
|
33
|
+
// 部门类标签(→ deptid 或 deptname)
|
|
34
|
+
const DEPT_LABEL = /申请部门|所属部门|部门|部门名称|单位|科室|组织/;
|
|
35
|
+
// 日期类标签(→ 今天)
|
|
36
|
+
const DATE_LABEL = /日期/;
|
|
37
|
+
// 时间类标签(结束时间/开始时间,不填默认值,避免时间字段误填日期)
|
|
38
|
+
const TIME_LABEL = /时间$/;
|
|
39
|
+
/**
|
|
40
|
+
* 按字段标签 + 类型,返回当前用户相关的默认值(无则 undefined)。
|
|
41
|
+
* htmltype: 3=浏览选择(给 id),1/2=文本(给名称)。
|
|
42
|
+
*/
|
|
43
|
+
export function defaultForField(label, htmltype, user) {
|
|
44
|
+
if (!label)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (PERSON_LABEL.test(label)) {
|
|
47
|
+
if (htmltype === 3)
|
|
48
|
+
return user.userid || undefined;
|
|
49
|
+
return user.username || undefined;
|
|
50
|
+
}
|
|
51
|
+
if (DEPT_LABEL.test(label)) {
|
|
52
|
+
if (htmltype === 3)
|
|
53
|
+
return user.deptid || undefined;
|
|
54
|
+
return user.deptname || undefined;
|
|
55
|
+
}
|
|
56
|
+
if (DATE_LABEL.test(label) && !TIME_LABEL.test(label)) {
|
|
57
|
+
return todayStr();
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|