hikvision-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.
Files changed (73) hide show
  1. package/dist/commands/binding.d.ts +6 -0
  2. package/dist/commands/binding.d.ts.map +1 -0
  3. package/dist/commands/binding.js +274 -0
  4. package/dist/commands/binding.js.map +1 -0
  5. package/dist/commands/card.d.ts +6 -0
  6. package/dist/commands/card.d.ts.map +1 -0
  7. package/dist/commands/card.js +259 -0
  8. package/dist/commands/card.js.map +1 -0
  9. package/dist/commands/group.d.ts +6 -0
  10. package/dist/commands/group.d.ts.map +1 -0
  11. package/dist/commands/group.js +87 -0
  12. package/dist/commands/group.js.map +1 -0
  13. package/dist/commands/org.d.ts +6 -0
  14. package/dist/commands/org.d.ts.map +1 -0
  15. package/dist/commands/org.js +248 -0
  16. package/dist/commands/org.js.map +1 -0
  17. package/dist/commands/person.d.ts +6 -0
  18. package/dist/commands/person.d.ts.map +1 -0
  19. package/dist/commands/person.js +563 -0
  20. package/dist/commands/person.js.map +1 -0
  21. package/dist/commands/service.d.ts +6 -0
  22. package/dist/commands/service.d.ts.map +1 -0
  23. package/dist/commands/service.js +153 -0
  24. package/dist/commands/service.js.map +1 -0
  25. package/dist/commands/sync.d.ts +6 -0
  26. package/dist/commands/sync.d.ts.map +1 -0
  27. package/dist/commands/sync.js +138 -0
  28. package/dist/commands/sync.js.map +1 -0
  29. package/dist/commands/system.d.ts +6 -0
  30. package/dist/commands/system.d.ts.map +1 -0
  31. package/dist/commands/system.js +167 -0
  32. package/dist/commands/system.js.map +1 -0
  33. package/dist/commands/vehicle.d.ts +12 -0
  34. package/dist/commands/vehicle.d.ts.map +1 -0
  35. package/dist/commands/vehicle.js +550 -0
  36. package/dist/commands/vehicle.js.map +1 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +94 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/services/hikvisionClient.d.ts +25 -0
  42. package/dist/services/hikvisionClient.d.ts.map +1 -0
  43. package/dist/services/hikvisionClient.js +59 -0
  44. package/dist/services/hikvisionClient.js.map +1 -0
  45. package/dist/utils/config.d.ts +66 -0
  46. package/dist/utils/config.d.ts.map +1 -0
  47. package/dist/utils/config.js +213 -0
  48. package/dist/utils/config.js.map +1 -0
  49. package/dist/utils/output.d.ts +42 -0
  50. package/dist/utils/output.d.ts.map +1 -0
  51. package/dist/utils/output.js +157 -0
  52. package/dist/utils/output.js.map +1 -0
  53. package/dist/utils/validation.d.ts +52 -0
  54. package/dist/utils/validation.d.ts.map +1 -0
  55. package/dist/utils/validation.js +171 -0
  56. package/dist/utils/validation.js.map +1 -0
  57. package/package.json +29 -0
  58. package/src/commands/binding.ts +305 -0
  59. package/src/commands/card.ts +238 -0
  60. package/src/commands/group.ts +91 -0
  61. package/src/commands/org.ts +228 -0
  62. package/src/commands/person.ts +596 -0
  63. package/src/commands/service.ts +174 -0
  64. package/src/commands/sync.ts +156 -0
  65. package/src/commands/system.ts +137 -0
  66. package/src/commands/vehicle.ts +572 -0
  67. package/src/index.ts +111 -0
  68. package/src/services/hikvisionClient.ts +74 -0
  69. package/src/types/cli-table3.d.ts +20 -0
  70. package/src/utils/config.ts +199 -0
  71. package/src/utils/output.ts +181 -0
  72. package/src/utils/validation.ts +160 -0
  73. package/tsconfig.json +19 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * 服务控制命令
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { success, error, info } from '../utils/output';
7
+
8
+ // Manager 服务地址(可通过环境变量覆盖)
9
+ const MANAGER_HOST = process.env.MANAGER_HOST || 'http://localhost:3001';
10
+ const API_KEY = process.env.MANAGER_API_KEY || '';
11
+
12
+ // 安全警告:检测到使用 HTTP 连接非本地地址时警告
13
+ function validateManagerHost(): void {
14
+ if (!MANAGER_HOST.startsWith('https://') && !MANAGER_HOST.includes('localhost') && !MANAGER_HOST.includes('127.0.0.1')) {
15
+ console.warn('⚠️ 安全警告:Manager 服务使用非安全连接 (HTTP),敏感信息可能被盗用');
16
+ }
17
+ }
18
+
19
+ validateManagerHost();
20
+
21
+
22
+ interface ServiceStatus {
23
+ isRunning: boolean;
24
+ pid: number | null;
25
+ port: number;
26
+ }
27
+
28
+ interface ApiResponse {
29
+ success: boolean;
30
+ message?: string;
31
+ data?: ServiceStatus;
32
+ pid?: number;
33
+ }
34
+
35
+ // 发送请求到 Manager
36
+ async function managerRequest(path: string, method: string = 'GET'): Promise<ApiResponse> {
37
+ const url = `${MANAGER_HOST}${path}`;
38
+ const headers: Record<string, string> = {};
39
+
40
+ // 添加 API Key 认证
41
+ if (API_KEY) {
42
+ headers['X-Api-Key'] = API_KEY;
43
+ }
44
+
45
+ try {
46
+ const res = await fetch(url, { method, headers });
47
+ const data = await res.json();
48
+ return data as ApiResponse;
49
+ } catch (err: any) {
50
+ throw new Error(`无法连接 Manager 服务 (${MANAGER_HOST}): ${err.message}`);
51
+ }
52
+ }
53
+
54
+ // 格式化运行时间
55
+ function formatUptime(seconds: number): string {
56
+ if (!seconds) return '-';
57
+ const h = Math.floor(seconds / 3600);
58
+ const m = Math.floor((seconds % 3600) / 60);
59
+ const s = Math.floor(seconds % 60);
60
+ return `${h}h ${m}m ${s}s`;
61
+ }
62
+
63
+ export const serviceCommands = new Command()
64
+ .name('service')
65
+ .description('API Server 服务控制');
66
+
67
+ // 查询服务状态
68
+ serviceCommands
69
+ .command('status')
70
+ .description('查询 API Server 服务状态')
71
+ .action(async () => {
72
+ try {
73
+ info('正在查询服务状态...');
74
+ const data = await managerRequest('/api/manager/status');
75
+
76
+ if (!data.success) {
77
+ error(data.message || '查询失败');
78
+ return;
79
+ }
80
+
81
+ const { isRunning, pid, port } = data.data || {};
82
+
83
+ if (isRunning) {
84
+ console.log('🟢 API Server 服务状态: 运行中');
85
+ console.log(` PID: ${pid || '-'}`);
86
+ console.log(` 端口: ${port || 3000}`);
87
+ } else {
88
+ console.log('🔴 API Server 服务状态: 已停止');
89
+ }
90
+ } catch (err: any) {
91
+ error(err.message);
92
+ }
93
+ });
94
+
95
+ // 启动服务
96
+ serviceCommands
97
+ .command('start')
98
+ .description('启动 API Server 服务')
99
+ .action(async () => {
100
+ try {
101
+ info('正在启动服务...');
102
+ const data = await managerRequest('/api/manager/start', 'POST');
103
+
104
+ if (data.success) {
105
+ success(data.message || '服务已启动');
106
+ } else {
107
+ error(data.message || '启动失败');
108
+ }
109
+ } catch (err: any) {
110
+ error(err.message);
111
+ }
112
+ });
113
+
114
+ // 停止服务
115
+ serviceCommands
116
+ .command('stop')
117
+ .description('停止 API Server 服务')
118
+ .action(async () => {
119
+ try {
120
+ info('正在停止服务...');
121
+ const data = await managerRequest('/api/manager/stop', 'POST');
122
+
123
+ if (data.success) {
124
+ success(data.message || '服务已停止');
125
+ } else {
126
+ error(data.message || '停止失败');
127
+ }
128
+ } catch (err: any) {
129
+ error(err.message);
130
+ }
131
+ });
132
+
133
+ // 重启服务
134
+ serviceCommands
135
+ .command('restart')
136
+ .description('重启 API Server 服务')
137
+ .action(async () => {
138
+ try {
139
+ info('正在重启服务...');
140
+ const data = await managerRequest('/api/manager/restart', 'POST');
141
+
142
+ if (data.success) {
143
+ success(data.message || '服务已重启');
144
+ } else {
145
+ error(data.message || '重启失败');
146
+ }
147
+ } catch (err: any) {
148
+ error(err.message);
149
+ }
150
+ });
151
+
152
+ // 查看 Manager 状态
153
+ serviceCommands
154
+ .command('info')
155
+ .description('查看 Manager 服务信息')
156
+ .action(async () => {
157
+ try {
158
+ info('正在查询 Manager 状态...');
159
+ const data = await managerRequest('/api/manager/status');
160
+
161
+ if (!data.success) {
162
+ error(data.message || '查询失败');
163
+ return;
164
+ }
165
+
166
+ console.log('📋 Manager 服务信息:');
167
+ console.log(` 地址: ${MANAGER_HOST}`);
168
+ console.log(` 状态: ${data.data?.isRunning ? '运行中' : '已停止'}`);
169
+ console.log(` API Server PID: ${data.data?.pid || '-'}`);
170
+ console.log(` API Server 端口: ${data.data?.port || 3000}`);
171
+ } catch (err: any) {
172
+ error(err.message);
173
+ }
174
+ });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * 数据同步命令
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { config } from '../utils/config';
7
+ import { success, error, formatOutput } from '../utils/output';
8
+ import { createHikvisionClient } from '../services/hikvisionClient';
9
+
10
+ export const syncCommands = new Command()
11
+ .command('sync')
12
+ .description('数据同步');
13
+
14
+ // 同步人员数据
15
+ syncCommands
16
+ .command('persons')
17
+ .description('同步人员数据(增量)')
18
+ .option('-s, --start <startTime>', '开始时间 (YYYY-MM-DD HH:mm:ss)')
19
+ .option('-e, --end <endTime>', '结束时间 (YYYY-MM-DD HH:mm:ss)', new Date().toISOString().slice(0, 19))
20
+ .action(async (options) => {
21
+ try {
22
+ const client = createHikvisionClient(config.get());
23
+
24
+ const result = await client.personService.syncIncrement(
25
+ options.start || new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().slice(0, 19),
26
+ options.end
27
+ );
28
+
29
+ console.log('📊 人员增量同步结果:');
30
+ console.log(` ✅ 新增: ${result.added.length} 条`);
31
+ console.log(` 🔄 修改: ${result.modified.length} 条`);
32
+ console.log(` ❌ 删除: ${result.deleted.length} 条`);
33
+
34
+ if (result.added.length > 0) {
35
+ console.log('\n新增人员:');
36
+ console.log(formatOutput(result.added));
37
+ }
38
+ if (result.modified.length > 0) {
39
+ console.log('\n修改人员:');
40
+ console.log(formatOutput(result.modified));
41
+ }
42
+ } catch (err: any) {
43
+ error(`同步人员数据失败: ${err.message || err}`);
44
+ }
45
+ });
46
+
47
+ // 同步卡片数据
48
+ syncCommands
49
+ .command('cards')
50
+ .description('同步卡片数据(增量)')
51
+ .option('-s, --start <startTime>', '开始时间 (YYYY-MM-DD HH:mm:ss)')
52
+ .option('-e, --end <endTime>', '结束时间 (YYYY-MM-DD HH:mm:ss)', new Date().toISOString().slice(0, 19))
53
+ .action(async (options) => {
54
+ try {
55
+ const client = createHikvisionClient(config.get());
56
+
57
+ const result = await client.cardService.syncIncrement(
58
+ options.start || new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().slice(0, 19),
59
+ options.end
60
+ );
61
+
62
+ console.log('📊 卡片增量同步结果:');
63
+ console.log(` ✅ 新增: ${result.added.length} 条`);
64
+ console.log(` 🔄 修改: ${result.modified.length} 条`);
65
+ console.log(` ❌ 删除: ${result.deleted.length} 条`);
66
+
67
+ if (result.added.length > 0) {
68
+ console.log('\n新增卡片:');
69
+ console.log(formatOutput(result.added));
70
+ }
71
+ } catch (err: any) {
72
+ error(`同步卡片数据失败: ${err.message || err}`);
73
+ }
74
+ });
75
+
76
+ // 同步车辆数据
77
+ syncCommands
78
+ .command('vehicles')
79
+ .description('同步车辆数据(增量)')
80
+ .option('-s, --start <startTime>', '开始时间 (YYYY-MM-DD HH:mm:ss)')
81
+ .option('-e, --end <endTime>', '结束时间 (YYYY-MM-DD HH:mm:ss)', new Date().toISOString().slice(0, 19))
82
+ .action(async (options) => {
83
+ try {
84
+ const client = createHikvisionClient(config.get());
85
+
86
+ const result = await client.vehicleService.syncIncrement(
87
+ options.start || new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().slice(0, 19),
88
+ options.end
89
+ );
90
+
91
+ console.log('📊 车辆增量同步结果:');
92
+ console.log(` ✅ 新增: ${result.added.length} 条`);
93
+ console.log(` 🔄 修改: ${result.modified.length} 条`);
94
+ console.log(` ❌ 删除: ${result.deleted.length} 条`);
95
+
96
+ if (result.added.length > 0) {
97
+ console.log('\n新增车辆:');
98
+ console.log(formatOutput(result.added));
99
+ }
100
+ } catch (err: any) {
101
+ error(`同步车辆数据失败: ${err.message || err}`);
102
+ }
103
+ });
104
+
105
+ // 全量同步
106
+ syncCommands
107
+ .command('full')
108
+ .description('全量同步所有数据')
109
+ .action(async () => {
110
+ try {
111
+ const client = createHikvisionClient(config.get());
112
+
113
+ console.log('🔄 开始全量同步...');
114
+
115
+ // 同步人员
116
+ console.log('\n📋 同步人员...');
117
+ let page = 1;
118
+ let allPersons: any[] = [];
119
+ while (true) {
120
+ const result = await client.personService.list({ pageNo: page, pageSize: 100 });
121
+ allPersons = allPersons.concat(result.list);
122
+ if (result.list.length < 100) break;
123
+ page++;
124
+ }
125
+ console.log(` ✅ 人员: ${allPersons.length} 条`);
126
+
127
+ // 同步卡片
128
+ console.log('\n📇 同步卡片...');
129
+ page = 1;
130
+ let allCards: any[] = [];
131
+ while (true) {
132
+ const result = await client.cardService.list({ pageNo: page, pageSize: 100 });
133
+ allCards = allCards.concat(result.list);
134
+ if (result.list.length < 100) break;
135
+ page++;
136
+ }
137
+ console.log(` ✅ 卡片: ${allCards.length} 条`);
138
+
139
+ // 同步车辆
140
+ console.log('\n🚗 同步车辆...');
141
+ page = 1;
142
+ let allVehicles: any[] = [];
143
+ while (true) {
144
+ const result = await client.vehicleService.list({ pageNo: page, pageSize: 100 });
145
+ allVehicles = allVehicles.concat(result.list);
146
+ if (result.list.length < 100) break;
147
+ page++;
148
+ }
149
+ console.log(` ✅ 车辆: ${allVehicles.length} 条`);
150
+
151
+ console.log('\n✅ 全量同步完成!');
152
+ console.log(`总计: ${allPersons.length + allCards.length + allVehicles.length} 条记录`);
153
+ } catch (err: any) {
154
+ error(`全量同步失败: ${err.message || err}`);
155
+ }
156
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * 系统管理命令
3
+ */
4
+
5
+ import { Command } from 'commander';
6
+ import { config } from '../utils/config';
7
+ import { success, error, info, formatOutput } from '../utils/output';
8
+
9
+ export const systemCommands = new Command()
10
+ .command('system')
11
+ .description('系统管理');
12
+
13
+ // 测试连接
14
+ systemCommands
15
+ .command('test')
16
+ .description('测试与海康平台连接')
17
+ .action(async () => {
18
+ try {
19
+ const cfg = config.get();
20
+ if (!cfg) {
21
+ error('未检测到配置,请先运行 `hikvision-cli config set` 进行配置');
22
+ return;
23
+ }
24
+ info(`正在连接海康平台: ${cfg.host}...`);
25
+
26
+ // 这里可以调用一个简单的 API 测试连接
27
+ // 暂时用组织查询作为连接测试
28
+ const { createHikvisionClient } = await import('../services/hikvisionClient');
29
+ const client = createHikvisionClient(cfg);
30
+
31
+ const orgs = await client.personService.getOrganizations();
32
+
33
+ success(`连接成功!平台返回 ${orgs.length} 个组织`);
34
+ } catch (err: any) {
35
+ error(`连接失败: ${err.message || err}`);
36
+ }
37
+ });
38
+
39
+ // 显示配置
40
+ systemCommands
41
+ .command('config')
42
+ .description('显示当前配置(敏感信息已脱敏)')
43
+ .action(() => {
44
+ const cfg = config.get();
45
+ if (!cfg) {
46
+ info('⚠️ 未检测到配置,请运行 `hikvision-cli config set` 进行配置');
47
+ return;
48
+ }
49
+ console.log('📋 当前配置(敏感信息已脱敏):');
50
+ console.log(formatOutput(config.maskSensitive(cfg)));
51
+ });
52
+
53
+ // 显示帮助
54
+ systemCommands
55
+ .command('help')
56
+ .description('显示帮助信息')
57
+ .action(() => {
58
+ console.log(`
59
+ 📖 Hikvision CLI 使用帮助
60
+
61
+ 🔧 基本用法:
62
+ hikvision-cli <command> [options]
63
+
64
+ 📋 可用命令:
65
+
66
+ person 人员管理
67
+ add 新增人员
68
+ list 查询人员列表
69
+ get 查询人员详情
70
+ update 修改人员
71
+ delete 删除人员
72
+ orgs 获取组织列表
73
+
74
+ card 卡片管理
75
+ bind 绑定卡片(将卡片与人员绑定)
76
+ list 查询卡片列表
77
+ unbind 退卡
78
+ loss 批量挂失
79
+ unloss 批量解挂
80
+
81
+ vehicle 车辆管理
82
+ add 添加/更新车辆
83
+ batch-add 批量添加车辆
84
+ list 查询车辆列表
85
+ get 查询车辆详情
86
+ delete 删除车辆
87
+ groups 查询车辆群组
88
+ add-group 添加车辆群组
89
+ delete-group 删除车辆群组
90
+
91
+ group 车辆群组管理
92
+ list 查询分组列表
93
+ add 添加分组
94
+ update 修改分组
95
+ delete 删除分组
96
+
97
+ org 组织管理
98
+ list 查询组织列表
99
+ get 查询组织详情
100
+ search 搜索组织
101
+
102
+ sync 数据同步
103
+ persons 同步人员数据
104
+ cards 同步卡片数据
105
+ vehicles 同步车辆数据
106
+ full 全量同步
107
+
108
+ system 系统管理
109
+ test 测试连接
110
+ config 显示配置
111
+ help 显示帮助
112
+
113
+ 💡 全局选项:
114
+ -h, --host <host> 海康平台主机地址
115
+ -k, --key <key> App Key
116
+ -s, --secret <secret> App Secret
117
+ -f, --format <format> 输出格式 (table|json|yaml)
118
+ -v, --verbose 详细输出
119
+
120
+ 📄 示例:
121
+ # 新增人员
122
+ hikvision-cli person add -n "张三" -p "13800138000" -o "root00000000"
123
+
124
+ # 查询人员列表
125
+ hikvision-cli person list -p 1 -s 20
126
+
127
+ # 批量开卡
128
+ hikvision-cli card issue -f cards.json
129
+
130
+ # 测试连接
131
+ hikvision-cli system test
132
+
133
+ # 全量同步
134
+ hikvision-cli sync full
135
+
136
+ `);
137
+ });