feat: 新增IM即时通讯(浮窗)、工作流、打印模块及工作台增强
- IM: 新增浮窗聊天(ImFloatWindow)、管理页(monitor/config/service/message)、SSE推送 - 工作流: 新增待办/我的流程页面及后端服务 - 打印: 新增打印模板、出库单打印(PrintPage)、模板种子脚本 - 工作台: 增强快捷入口与工作台数据 - 修复: TagsView页签关闭、CrudPage通用表格增强 - 移除导航菜单中的即时通讯入口,改为右下角浮窗
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 任务2 种子:简易工作流
|
||||
* 1) 创建「原料出库审批」流程定义 + 节点(开始 → 车间主管审批 → 结束)
|
||||
* 2) 创建侧边栏菜单:工作流(目录)→ 待办中心 / 我发起的
|
||||
* 用法:node server/scripts/seed-workflow.mjs
|
||||
*/
|
||||
const BASE = process.env.F9MES_API || 'http://localhost:5136';
|
||||
const PHONE = '13800000000';
|
||||
const PASSWORD = '123456';
|
||||
// 默认审批人:超级管理员(用户ID=1)
|
||||
const APPROVER_ID = 1;
|
||||
|
||||
async function api(h, method, url, body) {
|
||||
const res = await fetch(BASE + url, {
|
||||
method,
|
||||
headers: h,
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
});
|
||||
const text = await res.text();
|
||||
let json = null;
|
||||
try { json = JSON.parse(text); } catch { /* ignore */ }
|
||||
if (!res.ok || (json && json.code !== 0)) {
|
||||
throw new Error(`HTTP ${res.status} ${url}: ${text.slice(0, 300)}`);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const login = await api({ 'Content-Type': 'application/json' }, 'POST', '/api/auth/login', {
|
||||
phone: PHONE,
|
||||
password: PASSWORD,
|
||||
});
|
||||
const token = login.data.token;
|
||||
const h = { Authorization: 'Bearer ' + token, 'Content-Type': 'application/json' };
|
||||
|
||||
// ============ 1. 流程定义 ============
|
||||
const flows = (await api(h, 'GET', '/api/workflow/definitions?bizType=RawMaterial_OutStock')).data || [];
|
||||
let flow = flows.find((f) => f.code === 'RM_OUT_APPROVE');
|
||||
if (flow) {
|
||||
console.log('流程已存在:id=' + flow.id + ' name=' + flow.name + '(跳过创建)');
|
||||
} else {
|
||||
// 直接写库:Common_Workflow + Common_WorkflowNode(走通用 data 接口)
|
||||
const addFlow = await api(h, 'POST', '/api/data/Common_Workflow/add', {
|
||||
name: '原料出库审批',
|
||||
code: 'RM_OUT_APPROVE',
|
||||
bizType: 'RawMaterial_OutStock',
|
||||
status: 1,
|
||||
});
|
||||
const flowId = addFlow.data && (addFlow.data.id ?? addFlow.data);
|
||||
console.log('流程已创建 id=' + flowId);
|
||||
|
||||
const nodes = [
|
||||
{ workflowId: flowId, name: '发起', nodeType: 0, sort: 10 },
|
||||
{ workflowId: flowId, name: '车间主管审批', nodeType: 1, approverJson: JSON.stringify([APPROVER_ID]), sort: 20 },
|
||||
{ workflowId: flowId, name: '结束', nodeType: 4, sort: 99 },
|
||||
];
|
||||
for (const n of nodes) {
|
||||
const r = await api(h, 'POST', '/api/data/Common_WorkflowNode/add', n);
|
||||
console.log(' 节点「' + n.name + '」id=' + (r.data && (r.data.id ?? r.data)));
|
||||
}
|
||||
flow = { id: flowId };
|
||||
}
|
||||
|
||||
// ============ 2. 菜单 ============
|
||||
const menus = (await api(h, 'GET', '/api/data/BaseSys_Menu/all')).data || [];
|
||||
const items = (menus.items || (Array.isArray(menus) ? menus : []));
|
||||
let dir = items.find((m) => m.name === '工作流' && m.menuType === 0);
|
||||
if (!dir) {
|
||||
const r = await api(h, 'POST', '/api/data/BaseSys_Menu/add', {
|
||||
name: '工作流',
|
||||
menuType: 0,
|
||||
routePath: '',
|
||||
component: '',
|
||||
icon: 'Checked',
|
||||
isVisible: 1,
|
||||
isEnable: 1,
|
||||
sort: 999,
|
||||
parentId: 0,
|
||||
level: 0,
|
||||
path: '',
|
||||
});
|
||||
dir = { id: r.data && (r.data.id ?? r.data) };
|
||||
console.log('菜单目录「工作流」已创建 id=' + dir.id);
|
||||
} else {
|
||||
console.log('菜单目录「工作流」已存在 id=' + dir.id);
|
||||
}
|
||||
|
||||
const dirId = dir.id;
|
||||
const childDefs = [
|
||||
{ name: '待办中心', routePath: '/workflow/todo', component: 'WorkFlow/todo', icon: 'Bell', sort: 10 },
|
||||
{ name: '我发起的', routePath: '/workflow/my', component: 'WorkFlow/my', icon: 'Document', sort: 20 },
|
||||
];
|
||||
const refresh = (await api(h, 'GET', '/api/data/BaseSys_Menu/all')).data || {};
|
||||
const allMenus = refresh.items || (Array.isArray(refresh) ? refresh : []);
|
||||
for (const c of childDefs) {
|
||||
const exists = allMenus.find((m) => m.parentId === dirId && m.routePath === c.routePath);
|
||||
if (exists) {
|
||||
console.log('菜单「' + c.name + '」已存在 id=' + exists.id);
|
||||
continue;
|
||||
}
|
||||
const r = await api(h, 'POST', '/api/data/BaseSys_Menu/add', {
|
||||
name: c.name,
|
||||
menuType: 1,
|
||||
routePath: c.routePath,
|
||||
component: c.component,
|
||||
icon: c.icon,
|
||||
isVisible: 1,
|
||||
isEnable: 1,
|
||||
sort: c.sort,
|
||||
parentId: dirId,
|
||||
level: 1,
|
||||
path: '/' + dirId,
|
||||
});
|
||||
console.log('菜单「' + c.name + '」已创建 id=' + (r.data && (r.data.id ?? r.data)));
|
||||
}
|
||||
|
||||
console.log('\n完成。流程=' + (flow.id || '?') + '(原料出库审批 RM_OUT_APPROVE)');
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error('ERR: ' + e.message);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user