@peninsula-med/beisen-ehr-plugin 1.1.8 → 2.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/index.d.ts CHANGED
@@ -1,42 +1,24 @@
1
1
  import { OpenClawPlugin } from 'openclaw/plugin-sdk';
2
2
 
3
3
  /**
4
- * 北森 EHR OpenClaw Plugin
4
+ * 北森 EHR OpenClaw Plugin v2.0.0
5
5
  * 🐉 龙二 开发
6
6
  *
7
- * 功能:加班申请、考勤查询、假期余额、审批状态查询
7
+ * 完全移除 MCP 依赖,直接注册工具
8
8
  */
9
9
 
10
10
  declare const pluginId = "beisen-ehr-plugin";
11
- declare const pluginVersion = "1.1.8";
12
- /**
13
- * 北森 EHR 插件配置接口
14
- */
11
+ declare const pluginVersion = "2.0.0";
15
12
  interface BeisenEHRConfig {
16
- /** 北森 API 地址 */
17
13
  apiUrl?: string;
18
- /** App Key */
19
14
  appKey: string;
20
- /** App Secret */
21
15
  appSecret: string;
22
- /** 员工 ID */
23
16
  staffId: string;
24
- /** 企业租户 ID */
25
17
  tenantId: string;
26
- /** 企业邮箱 */
27
18
  email: string;
28
19
  }
29
- /**
30
- * 默认配置
31
- */
32
20
  declare const defaultConfig: Partial<BeisenEHRConfig>;
33
- /**
34
- * 插件注册函数
35
- */
36
21
  declare function register(api: any): Promise<void>;
37
- /**
38
- * 插件停用函数
39
- */
40
22
  declare function unregister(): Promise<void>;
41
23
  declare const plugin: OpenClawPlugin;
42
24
 
package/dist/index.esm.js CHANGED
@@ -3450,17 +3450,13 @@ var TypeBuilder = /*#__PURE__*/Object.freeze({
3450
3450
  const Type = TypeBuilder;
3451
3451
 
3452
3452
  /**
3453
- * 北森 EHR OpenClaw Plugin
3453
+ * 北森 EHR OpenClaw Plugin v2.0.0
3454
3454
  * 🐉 龙二 开发
3455
3455
  *
3456
- * 功能:加班申请、考勤查询、假期余额、审批状态查询
3456
+ * 完全移除 MCP 依赖,直接注册工具
3457
3457
  */
3458
- // 插件元数据
3459
3458
  const pluginId = 'beisen-ehr-plugin';
3460
- const pluginVersion = '1.1.8';
3461
- /**
3462
- * 默认配置
3463
- */
3459
+ const pluginVersion = '2.0.0';
3464
3460
  const defaultConfig = {
3465
3461
  apiUrl: 'https://openapi.italent.cn',
3466
3462
  };
@@ -3468,17 +3464,14 @@ const defaultConfig = {
3468
3464
  let cachedToken = null;
3469
3465
  let tokenExpiry = 0;
3470
3466
  async function getAccessToken(config) {
3471
- // 如果已有有效 Token,直接返回
3472
3467
  if (cachedToken && Date.now() < tokenExpiry) {
3473
3468
  return cachedToken;
3474
3469
  }
3475
- // 使用 AppKey + AppSecret 获取新 Token(北森官方格式)
3476
3470
  const tokenUrl = `${config.apiUrl || defaultConfig.apiUrl}/token`;
3471
+ console.error(`[BEISEN] 🔑 正在获取 Token: ${tokenUrl}`);
3477
3472
  const response = await fetch(tokenUrl, {
3478
3473
  method: "POST",
3479
- headers: {
3480
- "Content-Type": "application/json",
3481
- },
3474
+ headers: { "Content-Type": "application/json" },
3482
3475
  body: JSON.stringify({
3483
3476
  grant_type: "client_credentials",
3484
3477
  app_key: config.appKey,
@@ -3491,12 +3484,11 @@ async function getAccessToken(config) {
3491
3484
  }
3492
3485
  const data = await response.json();
3493
3486
  cachedToken = data.accessToken || data.access_token;
3494
- // Token 有效期通常 2 小时,提前 5 分钟刷新
3495
3487
  tokenExpiry = Date.now() + (data.expiresIn || data.expires_in || 7200) * 1000 - 5 * 60 * 1000;
3496
- console.error(`🔑 已获取新 Token,有效期至:${new Date(tokenExpiry).toISOString()}`);
3488
+ console.error(`[BEISEN] Token 获取成功,有效期至:${new Date(tokenExpiry).toISOString()}`);
3497
3489
  return cachedToken;
3498
3490
  }
3499
- // ============ 北森 API 客户端 ============
3491
+ // ============ API 客户端 ============
3500
3492
  class BeisenClient {
3501
3493
  constructor(config) {
3502
3494
  this.config = config;
@@ -3511,14 +3503,14 @@ class BeisenClient {
3511
3503
  ...(options.headers || {}),
3512
3504
  };
3513
3505
  const requestBody = options.body ? JSON.stringify(options.body) : undefined;
3514
- console.error(`📡 请求:${options.method || 'GET'} ${url}`);
3515
- console.error(`🔑 Token: ${token ? token.substring(0, 20) + '...' : 'none'}`);
3516
- console.error(`🏢 TenantId: ${this.config.tenantId}`);
3506
+ console.error(`[BEISEN] 📡 ${options.method || 'GET'} ${url}`);
3507
+ console.error(`[BEISEN] 🔑 Token: ${token.substring(0, 20)}...`);
3508
+ console.error(`[BEISEN] 🏢 TenantId: ${this.config.tenantId}`);
3517
3509
  if (requestBody) {
3518
- console.error(`📦 请求体:${requestBody.substring(0, 200)}...`);
3510
+ console.error(`[BEISEN] 📦 Body: ${requestBody.substring(0, 200)}`);
3519
3511
  }
3520
3512
  const controller = new AbortController();
3521
- const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 秒超时
3513
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
3522
3514
  try {
3523
3515
  const response = await fetch(url, {
3524
3516
  ...options,
@@ -3529,19 +3521,21 @@ class BeisenClient {
3529
3521
  clearTimeout(timeoutId);
3530
3522
  if (!response.ok) {
3531
3523
  const errorText = await response.text();
3532
- throw new Error(`北森 API 错误:${response.status} - ${errorText}`);
3524
+ throw new Error(`API 错误:${response.status} - ${errorText}`);
3533
3525
  }
3534
- return response.json();
3526
+ const result = await response.json();
3527
+ console.error(`[BEISEN] ✅ 响应:`, JSON.stringify(result).substring(0, 200));
3528
+ return result;
3535
3529
  }
3536
3530
  catch (error) {
3537
3531
  clearTimeout(timeoutId);
3538
3532
  if (error.name === 'AbortError') {
3539
- throw new Error('北森 API 请求超时(30 秒)');
3533
+ throw new Error('请求超时(30 秒)');
3540
3534
  }
3535
+ console.error(`[BEISEN] ❌ 错误:`, error.message);
3541
3536
  throw error;
3542
3537
  }
3543
3538
  }
3544
- // 提交加班申请(推送至北森系统并发起审批)
3545
3539
  async submitOvertime(data) {
3546
3540
  const overtimeData = {
3547
3541
  staffId: data.staffId,
@@ -3553,88 +3547,55 @@ class BeisenClient {
3553
3547
  if (data.properties) {
3554
3548
  overtimeData.properties = typeof data.properties === 'string' ? data.properties : JSON.stringify(data.properties);
3555
3549
  }
3556
- const payload = {
3557
- attendance_overTime: overtimeData,
3558
- };
3559
3550
  return this.request("/AttendanceOpen/api/v1/AttendanceOvertime/PostOverTimeWithApproval", {
3560
3551
  method: "POST",
3561
- body: payload,
3552
+ body: { attendance_overTime: overtimeData },
3562
3553
  });
3563
3554
  }
3564
- // 查询假期余额
3565
3555
  async getLeaveBalance(staffId, email) {
3566
3556
  return this.request("/AttendanceOpen/api/v1/LeaveBalance/QueryLeaveBalance", {
3567
3557
  method: "POST",
3568
3558
  body: { staffId, email },
3569
3559
  });
3570
3560
  }
3571
- // 查询考勤记录
3572
3561
  async getAttendanceRecords(startDate, endDate, employeeId) {
3573
3562
  return this.request("/api/v1/attendance/records", {
3574
3563
  method: "POST",
3575
3564
  body: { startDate, endDate, employeeId },
3576
3565
  });
3577
3566
  }
3578
- // 查询审批状态
3579
3567
  async getApprovalStatus(applicationId) {
3580
3568
  return this.request(`/api/v1/approval/${applicationId}/status`);
3581
3569
  }
3582
3570
  }
3583
- /**
3584
- * 插件注册函数
3585
- */
3571
+ // ============ 插件注册 ============
3586
3572
  async function register(api) {
3587
- console.error(`🏢 北森 EHR 插件已加载 v${pluginVersion}`);
3588
- // 获取插件配置
3573
+ console.error(`[BEISEN] 🏢 北森 EHR 插件 v${pluginVersion} 正在加载...`);
3589
3574
  const config = api.config?.plugins?.entries?.['beisen-ehr-plugin']?.config;
3590
- if (!config) {
3591
- console.error('⚠️ 插件已安装,但未配置凭证');
3592
- console.error('');
3593
- console.error('📝 请在 OpenClaw 配置中添加:');
3594
- console.error('');
3595
- console.error(' plugins: {');
3596
- console.error(' entries: {');
3597
- console.error(' "beisen-ehr-plugin": {');
3598
- console.error(' enabled: true,');
3599
- console.error(' config: {');
3600
- console.error(' appKey: "your-app-key",');
3601
- console.error(' appSecret: "your-app-secret",');
3602
- console.error(' staffId: "your-staff-id",');
3603
- console.error(' tenantId: "your-tenant-id",');
3604
- console.error(' email: "your-email@company.com"');
3605
- console.error(' }');
3606
- console.error(' }');
3607
- console.error(' }');
3608
- console.error(' }');
3609
- console.error('');
3610
- return;
3611
- }
3612
- // 验证必要配置
3613
- const requiredFields = ['appKey', 'appSecret', 'staffId', 'tenantId', 'email'];
3614
- const missingFields = requiredFields.filter(field => !config[field]);
3615
- if (missingFields.length > 0) {
3616
- console.error(`❌ 缺少必要配置:${missingFields.join(', ')}`);
3617
- console.error('请补充完整配置后重启 Gateway');
3575
+ if (!config || !config.appKey || !config.appSecret || !config.staffId || !config.tenantId || !config.email) {
3576
+ console.error('[BEISEN] ⚠️ 插件已安装,但未配置凭证');
3577
+ console.error('[BEISEN] 📝 请运行:npx @peninsula-med/beisen-ehr-configure');
3618
3578
  return;
3619
3579
  }
3620
- console.error('✅ 北森 EHR 配置验证通过');
3621
- console.error(`📡 API: ${config.apiUrl || defaultConfig.apiUrl}`);
3622
- console.error(`👤 员工:${config.staffId}`);
3623
- console.error(`🏢 企业:${config.tenantId}`);
3624
- // 创建 API 客户端
3580
+ console.error('[BEISEN] ✅ 配置验证通过');
3581
+ console.error(`[BEISEN] 📡 API: ${config.apiUrl || defaultConfig.apiUrl}`);
3582
+ console.error(`[BEISEN] 👤 StaffId: ${config.staffId}`);
3583
+ console.error(`[BEISEN] 🏢 TenantId: ${config.tenantId}`);
3584
+ console.error(`[BEISEN] 📧 Email: ${config.email}`);
3625
3585
  const client = new BeisenClient(config);
3626
3586
  // ============ 注册工具 ============
3627
- // 工具 1: 提交加班申请
3587
+ console.error('[BEISEN] 🔧 正在注册工具...');
3628
3588
  api.registerTool({
3629
3589
  name: 'beisen_submit_overtime',
3630
3590
  description: '提交加班申请到北森 EHR(推送数据并发起审批)',
3631
3591
  parameters: Type.Object({
3632
- startDate: Type.String({ description: '开始时间 (YYYY-MM-DD HH:mm:ss),如:2020-07-17 22:00:00' }),
3633
- stopDate: Type.String({ description: '结束时间 (YYYY-MM-DD HH:mm:ss),如:2020-07-17 23:00:00' }),
3634
- compensationType: Type.Optional(Type.Number({ description: '补偿类型:0=调休假,1=加班费(默认 0)' })),
3635
- properties: Type.Optional(Type.String({ description: '自定义字段 JSON 字符串' })),
3592
+ startDate: Type.String({ description: '开始时间 (YYYY-MM-DD HH:mm:ss)' }),
3593
+ stopDate: Type.String({ description: '结束时间 (YYYY-MM-DD HH:mm:ss)' }),
3594
+ compensationType: Type.Optional(Type.Number({ description: '补偿类型:0=调休假,1=加班费' })),
3595
+ properties: Type.Optional(Type.String({ description: '自定义字段 JSON' })),
3636
3596
  }),
3637
3597
  async execute(_id, params) {
3598
+ console.error(`[BEISEN] 🔨 工具调用:beisen_submit_overtime`, JSON.stringify(params));
3638
3599
  try {
3639
3600
  const result = await client.submitOvertime({
3640
3601
  staffId: config.staffId,
@@ -3644,22 +3605,16 @@ async function register(api) {
3644
3605
  compensationType: params.compensationType,
3645
3606
  properties: params.properties,
3646
3607
  });
3647
- if (result.code === "200" || result.code === 200) {
3648
- const compTypeText = params.compensationType === 1 ? "加班费" : "调休假";
3649
- return {
3650
- content: [
3651
- {
3652
- type: "text",
3653
- text: `✅ 加班申请已提交!\n\n申请详情:\n- 员工 ID: ${config.staffId}\n- 邮箱:${config.email}\n- 开始:${params.startDate}\n- 结束:${params.stopDate}\n- 补偿类型:${compTypeText}\n- 申请 ID: ${result.data || "待返回"}`,
3654
- },
3655
- ],
3656
- };
3657
- }
3658
- else {
3659
- throw new Error(result.message || `API 返回错误:${result.code}`);
3660
- }
3608
+ const compTypeText = params.compensationType === 1 ? "加班费" : "调休假";
3609
+ return {
3610
+ content: [{
3611
+ type: "text",
3612
+ text: `✅ 加班申请已提交!\n\n- 员工:${config.staffId}\n- 邮箱:${config.email}\n- 时间:${params.startDate} ~ ${params.stopDate}\n- 类型:${compTypeText}`,
3613
+ }],
3614
+ };
3661
3615
  }
3662
3616
  catch (error) {
3617
+ console.error(`[BEISEN] ❌ 提交失败:`, error.message);
3663
3618
  return {
3664
3619
  content: [{ type: "text", text: `❌ 提交失败:${error.message}` }],
3665
3620
  isError: true,
@@ -3667,31 +3622,27 @@ async function register(api) {
3667
3622
  }
3668
3623
  },
3669
3624
  });
3670
- // 工具 2: 查询假期余额
3671
3625
  api.registerTool({
3672
3626
  name: 'beisen_get_leave_balance',
3673
3627
  description: '查询假期余额(年假、调休假等)',
3674
3628
  parameters: Type.Object({}),
3675
3629
  async execute(_id, _params) {
3630
+ console.error(`[BEISEN] 🔨 工具调用:beisen_get_leave_balance`);
3676
3631
  try {
3677
3632
  const result = await client.getLeaveBalance(config.staffId, config.email);
3678
- let balanceText = `📊 假期余额查询\n\n员工:${config.email}\n\n`;
3633
+ let balanceText = `📊 假期余额\n\n员工:${config.email}\n\n`;
3679
3634
  if (result.data && Array.isArray(result.data)) {
3680
3635
  result.data.forEach((item) => {
3681
- balanceText += `• ${item.leaveTypeName || item.typeName || '未知假期'}: ${item.balanceDays || item.balance || 0} 天\n`;
3636
+ balanceText += `• ${item.leaveTypeName || item.typeName || '未知'}: ${item.balanceDays || item.balance || 0} 天\n`;
3682
3637
  });
3683
3638
  }
3684
- else if (result.data) {
3685
- balanceText += JSON.stringify(result.data, null, 2);
3686
- }
3687
3639
  else {
3688
- balanceText += "暂无假期数据";
3640
+ balanceText += "暂无数据";
3689
3641
  }
3690
- return {
3691
- content: [{ type: "text", text: balanceText }],
3692
- };
3642
+ return { content: [{ type: "text", text: balanceText }] };
3693
3643
  }
3694
3644
  catch (error) {
3645
+ console.error(`[BEISEN] ❌ 查询失败:`, error.message);
3695
3646
  return {
3696
3647
  content: [{ type: "text", text: `❌ 查询失败:${error.message}` }],
3697
3648
  isError: true,
@@ -3699,7 +3650,6 @@ async function register(api) {
3699
3650
  }
3700
3651
  },
3701
3652
  });
3702
- // 工具 3: 查询考勤记录
3703
3653
  api.registerTool({
3704
3654
  name: 'beisen_query_attendance',
3705
3655
  description: '查询员工考勤记录',
@@ -3708,18 +3658,15 @@ async function register(api) {
3708
3658
  endDate: Type.String({ description: '结束日期 (YYYY-MM-DD)' }),
3709
3659
  }),
3710
3660
  async execute(_id, params) {
3661
+ console.error(`[BEISEN] 🔨 工具调用:beisen_query_attendance`, JSON.stringify(params));
3711
3662
  try {
3712
3663
  const records = await client.getAttendanceRecords(params.startDate, params.endDate, config.staffId);
3713
3664
  return {
3714
- content: [
3715
- {
3716
- type: "text",
3717
- text: `📅 考勤记录 (${params.startDate} ~ ${params.endDate})\n\n${JSON.stringify(records, null, 2)}`,
3718
- },
3719
- ],
3665
+ content: [{ type: "text", text: `📅 考勤记录\n\n${JSON.stringify(records, null, 2)}` }],
3720
3666
  };
3721
3667
  }
3722
3668
  catch (error) {
3669
+ console.error(`[BEISEN] ❌ 查询失败:`, error.message);
3723
3670
  return {
3724
3671
  content: [{ type: "text", text: `❌ 查询失败:${error.message}` }],
3725
3672
  isError: true,
@@ -3727,7 +3674,6 @@ async function register(api) {
3727
3674
  }
3728
3675
  },
3729
3676
  });
3730
- // 工具 4: 查询审批状态
3731
3677
  api.registerTool({
3732
3678
  name: 'beisen_get_approval_status',
3733
3679
  description: '查询审批状态',
@@ -3735,18 +3681,18 @@ async function register(api) {
3735
3681
  applicationId: Type.String({ description: '申请 ID' }),
3736
3682
  }),
3737
3683
  async execute(_id, params) {
3684
+ console.error(`[BEISEN] 🔨 工具调用:beisen_get_approval_status`, JSON.stringify(params));
3738
3685
  try {
3739
3686
  const status = await client.getApprovalStatus(params.applicationId);
3740
3687
  return {
3741
- content: [
3742
- {
3688
+ content: [{
3743
3689
  type: "text",
3744
- text: `📋 审批状态\n\n申请 ID: ${params.applicationId}\n状态:${status.status || "未知"}\n审批人:${status.approver || "待分配"}\n备注:${status.remark || "无"}`,
3745
- },
3746
- ],
3690
+ text: `📋 审批状态\n\nID: ${params.applicationId}\n状态:${status.status || "未知"}\n审批人:${status.approver || "待分配"}`,
3691
+ }],
3747
3692
  };
3748
3693
  }
3749
3694
  catch (error) {
3695
+ console.error(`[BEISEN] ❌ 查询失败:`, error.message);
3750
3696
  return {
3751
3697
  content: [{ type: "text", text: `❌ 查询失败:${error.message}` }],
3752
3698
  isError: true,
@@ -3754,15 +3700,12 @@ async function register(api) {
3754
3700
  }
3755
3701
  },
3756
3702
  });
3757
- console.error('✅ 已注册 4 个工具:beisen_submit_overtime, beisen_get_leave_balance, beisen_query_attendance, beisen_get_approval_status');
3703
+ console.error('[BEISEN] ✅ 已注册 4 个工具');
3704
+ console.error('[BEISEN] 🎉 插件加载完成,准备就绪!');
3758
3705
  }
3759
- /**
3760
- * 插件停用函数
3761
- */
3762
3706
  async function unregister() {
3763
- console.error('🏢 北森 EHR 插件已停用');
3707
+ console.error('[BEISEN] 🏢 插件已停用');
3764
3708
  }
3765
- // 导出插件入口
3766
3709
  const plugin = {
3767
3710
  id: pluginId,
3768
3711
  version: pluginVersion,