/ clis / boss / batchgreet.js
batchgreet.js
 1  /**
 2   * BOSS直聘 batchgreet — batch greet recommended candidates.
 3   */
 4  import { cli, Strategy } from '@jackwener/opencli/registry';
 5  import { requirePage, navigateToChat, fetchRecommendList, clickCandidateInList, typeAndSendMessage, verbose, } from './utils.js';
 6  cli({
 7      site: 'boss',
 8      name: 'batchgreet',
 9      description: 'BOSS直聘批量向推荐候选人发送招呼',
10      domain: 'www.zhipin.com',
11      strategy: Strategy.COOKIE,
12      navigateBefore: false,
13      browser: true,
14      args: [
15          { name: 'job-id', default: '', help: 'Filter by encrypted job ID (greet all jobs if empty)' },
16          { name: 'limit', type: 'int', default: 5, help: 'Max candidates to greet' },
17          { name: 'text', default: '', help: 'Custom greeting message (uses default if empty)' },
18      ],
19      columns: ['name', 'status', 'detail'],
20      func: async (page, kwargs) => {
21          requirePage(page);
22          const filterJobId = kwargs['job-id'] || '';
23          const limit = kwargs.limit || 5;
24          const text = kwargs.text || '你好,请问您对这个职位感兴趣吗?';
25          verbose(`Batch greeting up to ${limit} candidates...`);
26          await navigateToChat(page, 3);
27          let candidates = await fetchRecommendList(page);
28          if (filterJobId) {
29              candidates = candidates.filter((f) => f.encryptJobId === filterJobId);
30          }
31          candidates = candidates.slice(0, limit);
32          if (candidates.length === 0) {
33              return [{ name: '-', status: '⚠️ 无候选人', detail: '当前没有待招呼的推荐候选人' }];
34          }
35          const results = [];
36          for (const candidate of candidates) {
37              const numericUid = candidate.uid;
38              const friendName = candidate.name || '候选人';
39              try {
40                  const clicked = await clickCandidateInList(page, numericUid);
41                  if (!clicked) {
42                      results.push({ name: friendName, status: '❌ 跳过', detail: '在聊天列表中未找到' });
43                      continue;
44                  }
45                  await page.wait({ time: 2 });
46                  const sent = await typeAndSendMessage(page, text);
47                  if (!sent) {
48                      results.push({ name: friendName, status: '❌ 失败', detail: '找不到消息输入框' });
49                      continue;
50                  }
51                  await page.wait({ time: 1.5 });
52                  results.push({ name: friendName, status: '✅ 已发送', detail: text });
53              }
54              catch (e) {
55                  results.push({ name: friendName, status: '❌ 失败', detail: e.message?.substring(0, 80) || '未知错误' });
56              }
57          }
58          return results;
59      },
60  });