api.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #!/usr/bin/env node
  2. // 智能工牌录音管道 API 工具(零依赖, Node >=18)
  3. // 用法:
  4. // node api.mjs login <密码> # 登录并缓存 token 到 scripts/.token
  5. // node api.mjs get /api/archive/missing
  6. // node api.mjs post /api/archive/run '{"dates":["2026-09-03"]}'
  7. // node api.mjs env # 查看连接诊断(BASE / 是否已登录)
  8. // node api.mjs get /api/reports --raw # 输出完整响应(含 code/message)
  9. // node api.mjs get /api/reports --base http://localhost:3002 # 指定接口地址
  10. // 环境变量: SMARTBADGE_API_BASE(默认线上 https://recording.sh-lami.com)、
  11. // SMARTBADGE_USERNAME(默认 lami123456)、SMARTBADGE_PASSWORD(或参数传入)
  12. import { baseUrl, fail, login, httpJson, loadToken, TOKEN_FILE } from './lib.mjs';
  13. const args = process.argv.slice(2);
  14. const positional = [];
  15. let baseOverride;
  16. let rawFlag = false;
  17. for (let i = 0; i < args.length; i++) {
  18. const a = args[i];
  19. if (a === '--raw') rawFlag = true;
  20. else if (a === '--base') baseOverride = args[++i];
  21. else positional.push(a);
  22. }
  23. const [cmd, apiPath, bodyStr] = positional;
  24. async function main() {
  25. if (cmd === 'login') {
  26. const token = await login({
  27. base: baseUrl(baseOverride),
  28. username: process.env.SMARTBADGE_USERNAME,
  29. password: process.env.SMARTBADGE_PASSWORD || apiPath,
  30. });
  31. console.log(`登录成功, token 已缓存(${token.slice(0, 8)}...)`);
  32. return;
  33. }
  34. if (cmd === 'env') {
  35. const token = loadToken();
  36. console.log(`BASE = ${baseUrl(baseOverride)}`);
  37. console.log(`USERNAME= ${process.env.SMARTBADGE_USERNAME || 'lami123456'}`);
  38. console.log(`TOKEN = ${token ? `已登录 (${token.slice(0, 8)}... @ ${TOKEN_FILE})` : '未登录(先: node api.mjs login <密码>)'}`);
  39. return;
  40. }
  41. if (!cmd || !apiPath) fail('用法: node api.mjs login|env|get|post|put|delete <路径> [JSON体] [--raw] [--base URL]');
  42. const body = bodyStr !== undefined && bodyStr.trim() ? JSON.parse(bodyStr) : undefined;
  43. const r = await httpJson(cmd, apiPath, body, { base: baseOverride, raw: rawFlag });
  44. if (r.status >= 400 && r.json?.code !== 0 && !rawFlag) {
  45. fail(`请求失败(${r.status}): ${JSON.stringify(r.json)}`);
  46. }
  47. if (rawFlag) {
  48. console.log(JSON.stringify(r.json, null, 2));
  49. } else {
  50. const data = r.json?.data;
  51. console.log(data === undefined || data === null
  52. ? `(${r.status}) ${r.json?.message || 'no data'}`
  53. : JSON.stringify(data, null, 2));
  54. }
  55. if (!r.ok && process.env.SMARTBADGE_DEBUG) fail(`HTTP ${r.status}`, 1);
  56. }
  57. main().catch((err) => {
  58. if (err instanceof SyntaxError && /JSON/i.test(err.message)) {
  59. fail(`JSON 体解析失败: ${err.message}\n 示例: node api.mjs post /api/archive/run '{"dates":["2026-09-03"]}'`);
  60. }
  61. fail(err.message);
  62. });