qmai-cli-public 0.1.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.
@@ -0,0 +1,46 @@
1
+ version: 2
2
+
3
+ project_name: qmai
4
+
5
+ before:
6
+ hooks:
7
+ - go mod tidy
8
+
9
+ builds:
10
+ - id: qmai
11
+ main: ./main.go
12
+ binary: qmai
13
+ env:
14
+ - CGO_ENABLED=0
15
+ goos:
16
+ - darwin
17
+ - linux
18
+ - windows
19
+ goarch:
20
+ - amd64
21
+ - arm64
22
+ ldflags:
23
+ - -s -w
24
+ - -X main.version={{ .Version }}
25
+ - -X main.commit={{ .Commit }}
26
+ - -X main.date={{ .Date }}
27
+
28
+ archives:
29
+ - id: qmai-archive
30
+ builds:
31
+ - qmai
32
+ formats:
33
+ - tar.gz
34
+ format_overrides:
35
+ - goos: windows
36
+ formats:
37
+ - zip
38
+ name_template: "qmai_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
39
+
40
+ checksum:
41
+ name_template: "checksums.txt"
42
+
43
+ release:
44
+ github:
45
+ owner: feixiao629
46
+ name: qmai-cli-public
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qmai-cli contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # qmai-cli
2
+
3
+ 企迈开放平台命令行工具,面向商品、门店组织、会员、营销、订单、财务、聚合配送、进销存和排队等业务场景,提供统一的命令行调用入口,并支持通过 npm 全局安装。
4
+
5
+ 为什么选 qmai-cli? · 工具能力项 · 安装与快速开始 · 常用命令 · 认证与配置 · 安全与声明
6
+
7
+ ## 为什么选 qmai-cli?
8
+
9
+ - 统一命令入口:围绕企迈开放平台常见业务域提供一致的 CLI 结构
10
+ - 适合自动化:支持脚本调用、批量处理和结构化输出
11
+ - 凭证分层存储:敏感密钥走系统 keychain,非敏感配置走本地 profile
12
+ - 面向实际运维和联调:支持查询、变更、批量导入导出和原始 API 调试
13
+
14
+ ## 工具能力项
15
+
16
+ ### 商品
17
+
18
+ - 商品列表、详情查询
19
+ - 商品创建、更新、删除
20
+ - 商品上下架、估清、售罄、库存相关操作
21
+ - 批量调价、批量状态变更
22
+ - 商品导入、导出
23
+
24
+ ### 门店与组织
25
+
26
+ - 门店详情、门店列表查询
27
+ - 门店编码与门店 ID 转换
28
+ - 组织树、团队列表、部门树查询
29
+ - 门店状态修改、门店归属团队调整
30
+ - 门店资料同步
31
+
32
+ ### 会员
33
+
34
+ - 积分、余额、优惠券等资产查询
35
+ - 会员检索、基础资料查询
36
+ - openId、动态码、条件查询等辅助能力
37
+ - 标签查询、标签创建、会员打标
38
+ - 冻结、注销、换绑手机号等会员操作入口
39
+
40
+ ### 营销
41
+
42
+ - 优惠券状态、营销活动查询
43
+ - 礼品卡信息、发卡、核销、兑换等操作
44
+ - 优惠券模板启用、发券活动相关能力
45
+ - 营销定价确认
46
+
47
+ ### 订单
48
+
49
+ - 用户订单、订单详情、订单状态查询
50
+ - 评价回复
51
+ - 订单上报、已完成订单上报、已退款订单上报
52
+
53
+ ### 财务
54
+
55
+ - 分账明细查询
56
+ - 微信账单与账单下载地址查询
57
+ - 营业汇总、商品销售汇总等统计能力
58
+
59
+ ### 聚合配送
60
+
61
+ - 配送单创建、取消、详情查询
62
+ - 骑手位置查询
63
+ - 配送状态同步
64
+
65
+ ### 进销存
66
+
67
+ - 订货、调拨、退货单查询与处理
68
+ - 入库、出库、库存占用等库存操作
69
+ - 商品、供应商、半成品成本卡等基础资料维护
70
+
71
+ ### 排队
72
+
73
+ - 门店排队进度查询
74
+ - 订单排队进度查询
75
+ - 门店叫号列表查询
76
+
77
+ ### 平台调试与辅助能力
78
+
79
+ - 原始 API 透传
80
+ - 环境诊断
81
+ - shell 自动补全
82
+
83
+ ## 安装与快速开始
84
+
85
+ ### 环境要求
86
+
87
+ - Node.js `18+`
88
+ - 可访问企迈开放平台的合法账号与授权信息
89
+ - 本机支持系统 keychain 或等价安全存储
90
+
91
+ ### 通过 npm 安装
92
+
93
+ ```bash
94
+ npm install -g qmai-cli-public
95
+ qmai version
96
+ ```
97
+
98
+ 说明:
99
+
100
+ - npm 安装会自动下载当前平台对应的预编译二进制
101
+ - 普通使用者不需要额外安装 Go
102
+
103
+ ### 从源码构建
104
+
105
+ 源码安装需要:
106
+
107
+ - Go `1.23.0+`
108
+
109
+ ```bash
110
+ make build
111
+ ./bin/qmai version
112
+ ```
113
+
114
+ ### 从源码安装
115
+
116
+ ```bash
117
+ make install
118
+ qmai version
119
+ ```
120
+
121
+ ### 初始化与认证
122
+
123
+ ```bash
124
+ qmai config init
125
+ qmai auth login
126
+ qmai doctor
127
+ ```
128
+
129
+ ## 常用命令
130
+
131
+ ### 商品
132
+
133
+ ```bash
134
+ qmai product list
135
+ qmai product get <id|name>
136
+ qmai product create --name "美式咖啡" --price 28.00 --trade-no P001
137
+ qmai product batch-status --action up --trade-marks TM001,TM002
138
+ ```
139
+
140
+ ### 门店与组织
141
+
142
+ ```bash
143
+ qmai store get <shop-code>
144
+ qmai store list --keyword 门店名
145
+ qmai store org-tree
146
+ qmai store team-list
147
+ ```
148
+
149
+ ### 会员
150
+
151
+ ```bash
152
+ qmai member asset points --customer-id C001
153
+ qmai member profile search --phone 13800138000
154
+ qmai member tag list --customer-id C001
155
+ qmai member profile freeze --customer-id C001 --reason "风险处理" --dry-run
156
+ ```
157
+
158
+ ### 订单与财务
159
+
160
+ ```bash
161
+ qmai order query status --order-no O20260407001
162
+ qmai order report upload --from-json order-upload.json
163
+ qmai finance statement split-flows --created-at-start "2026-04-01 00:00:00" --created-at-end "2026-04-07 23:59:59"
164
+ qmai finance stats business-summary --shop-code S001 --start-date 2026-04-01 --end-date 2026-04-07
165
+ ```
166
+
167
+ ### 配送、进销存与排队
168
+
169
+ ```bash
170
+ qmai delivery order detail --order-source 1 --origin-order-no O20260407001
171
+ qmai inventory stock realtime-list --warehouse-nos CK001 --page 1 --page-size 20
172
+ qmai queue order-progress --order-no O20260407001
173
+ ```
174
+
175
+ ### 原始 API 与补全
176
+
177
+ ```bash
178
+ qmai api v3/goods/item/getItemList --body '{"shopCode":"S001"}'
179
+ qmai completion zsh
180
+ ```
181
+
182
+ ## 认证与配置
183
+
184
+ - 配置文件:`~/.config/qmai/config.yaml`
185
+ - 敏感信息:`openKey` 存储在操作系统 keychain 中
186
+ - 非敏感信息:`openId`、`grantCode`、`shopCode` 存在 profile 配置中
187
+ - 全局参数:`--profile`、`--format`、`--debug`
188
+
189
+ 常用配置命令:
190
+
191
+ ```bash
192
+ qmai config list
193
+ qmai config profile add store2 --shop-code S002
194
+ qmai config profile list
195
+ qmai config set active_profile store2
196
+ ```
197
+
198
+ ## 安全与声明
199
+
200
+ - 请使用你自己的企迈开放平台凭证,并确保拥有目标资源的合法访问权限
201
+ - 本仓库不提供真实凭证、真实门店信息或内部文档摘录
202
+ - 示例参数仅用于演示,不代表真实生产数据
203
+ - 这不是企迈官方项目
204
+ - `Qmai` 及相关产品名称归其各自权利人所有
205
+ - 使用本软件时,你需要自行遵守对应平台的服务条款、接口文档和授权要求
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const path = require("node:path");
5
+
6
+ const binaryPath = path.join(
7
+ __dirname,
8
+ "..",
9
+ "dist",
10
+ process.platform === "win32" ? "qmai.exe" : "qmai"
11
+ );
12
+
13
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
14
+ stdio: "inherit",
15
+ });
16
+
17
+ if (result.error) {
18
+ console.error("无法启动 qmai 二进制文件:", result.error.message);
19
+ process.exit(1);
20
+ }
21
+
22
+ process.exit(result.status === null ? 1 : result.status);
package/npm/install.js ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const fsp = require("node:fs/promises");
5
+ const https = require("node:https");
6
+ const path = require("node:path");
7
+ const { spawnSync } = require("node:child_process");
8
+
9
+ const packageRoot = path.resolve(__dirname, "..");
10
+ const distDir = path.join(packageRoot, "npm", "dist");
11
+ const packageJson = require(path.join(packageRoot, "package.json"));
12
+
13
+ const platformMap = {
14
+ darwin: "darwin",
15
+ linux: "linux",
16
+ win32: "windows",
17
+ };
18
+
19
+ const archMap = {
20
+ x64: "amd64",
21
+ arm64: "arm64",
22
+ };
23
+
24
+ function fail(message) {
25
+ console.error(message);
26
+ process.exit(1);
27
+ }
28
+
29
+ function runCommand(command, args) {
30
+ const result = spawnSync(command, args, { stdio: "inherit" });
31
+ if (result.error || result.status !== 0) {
32
+ fail(`qmai-cli-public 安装失败:执行 ${command} ${args.join(" ")} 失败`);
33
+ }
34
+ }
35
+
36
+ function getPlatform() {
37
+ const mapped = platformMap[process.platform];
38
+ if (!mapped) {
39
+ fail(`qmai-cli-public 当前不支持平台 ${process.platform}`);
40
+ }
41
+ return mapped;
42
+ }
43
+
44
+ function getArch() {
45
+ const mapped = archMap[process.arch];
46
+ if (!mapped) {
47
+ fail(`qmai-cli-public 当前不支持架构 ${process.arch}`);
48
+ }
49
+ return mapped;
50
+ }
51
+
52
+ function getAssetInfo() {
53
+ const version = packageJson.version;
54
+ const platform = getPlatform();
55
+ const arch = getArch();
56
+ const baseName = `qmai_${version}_${platform}_${arch}`;
57
+ const archiveName = platform === "windows" ? `${baseName}.zip` : `${baseName}.tar.gz`;
58
+ const binaryName = platform === "windows" ? "qmai.exe" : "qmai";
59
+ return { version, platform, arch, baseName, archiveName, binaryName };
60
+ }
61
+
62
+ function getDownloadUrl(archiveName) {
63
+ const customUrl = process.env.QMAI_CLI_DOWNLOAD_URL;
64
+ if (customUrl) {
65
+ return customUrl;
66
+ }
67
+
68
+ const baseUrl =
69
+ process.env.QMAI_CLI_RELEASE_BASE_URL ||
70
+ "https://github.com/madaima/qmai-cli-public/releases/download";
71
+ return `${baseUrl}/v${packageJson.version}/${archiveName}`;
72
+ }
73
+
74
+ async function downloadFile(url, outputPath) {
75
+ await new Promise((resolve, reject) => {
76
+ const file = fs.createWriteStream(outputPath);
77
+ const request = https.get(
78
+ url,
79
+ {
80
+ headers: {
81
+ "User-Agent": "qmai-cli-public-installer",
82
+ Accept: "application/octet-stream",
83
+ },
84
+ },
85
+ (response) => {
86
+ if (
87
+ response.statusCode &&
88
+ response.statusCode >= 300 &&
89
+ response.statusCode < 400 &&
90
+ response.headers.location
91
+ ) {
92
+ file.close();
93
+ fs.unlinkSync(outputPath);
94
+ downloadFile(response.headers.location, outputPath).then(resolve).catch(reject);
95
+ return;
96
+ }
97
+
98
+ if (response.statusCode !== 200) {
99
+ file.close();
100
+ fs.unlinkSync(outputPath);
101
+ reject(
102
+ new Error(`download failed: ${response.statusCode} ${response.statusMessage || ""}`.trim())
103
+ );
104
+ return;
105
+ }
106
+
107
+ response.pipe(file);
108
+ file.on("finish", () => file.close(resolve));
109
+ }
110
+ );
111
+
112
+ request.on("error", (error) => {
113
+ file.close();
114
+ if (fs.existsSync(outputPath)) {
115
+ fs.unlinkSync(outputPath);
116
+ }
117
+ reject(error);
118
+ });
119
+ });
120
+ }
121
+
122
+ async function extractArchive(archivePath, targetDir, platform) {
123
+ if (platform === "windows") {
124
+ runCommand("powershell.exe", [
125
+ "-NoProfile",
126
+ "-Command",
127
+ `Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${targetDir}' -Force`,
128
+ ]);
129
+ return;
130
+ }
131
+
132
+ runCommand("tar", ["-xzf", archivePath, "-C", targetDir]);
133
+ }
134
+
135
+ async function copyLocalAsset(localAssetDir, archiveName, outputPath) {
136
+ const sourcePath = path.join(localAssetDir, archiveName);
137
+ await fsp.copyFile(sourcePath, outputPath);
138
+ }
139
+
140
+ async function main() {
141
+ const { archiveName, baseName, binaryName, platform } = getAssetInfo();
142
+ const archivePath = path.join(distDir, archiveName);
143
+ const extractedDir = path.join(distDir, baseName);
144
+ const finalBinaryPath = path.join(distDir, binaryName);
145
+
146
+ await fsp.mkdir(distDir, { recursive: true });
147
+ await fsp.rm(archivePath, { force: true });
148
+ await fsp.rm(extractedDir, { recursive: true, force: true });
149
+ await fsp.rm(finalBinaryPath, { force: true });
150
+
151
+ const localAssetDir = process.env.QMAI_CLI_LOCAL_ASSET_DIR;
152
+ if (localAssetDir) {
153
+ await copyLocalAsset(localAssetDir, archiveName, archivePath);
154
+ } else {
155
+ const url = getDownloadUrl(archiveName);
156
+ console.log(`下载 qmai 二进制:${url}`);
157
+ await downloadFile(url, archivePath);
158
+ }
159
+
160
+ await extractArchive(archivePath, distDir, platform);
161
+
162
+ const extractedBinaryPath = path.join(extractedDir, binaryName);
163
+ if (!fs.existsSync(extractedBinaryPath)) {
164
+ fail(`qmai-cli-public 安装失败:未在压缩包中找到 ${binaryName}`);
165
+ }
166
+
167
+ await fsp.copyFile(extractedBinaryPath, finalBinaryPath);
168
+ if (platform !== "windows") {
169
+ await fsp.chmod(finalBinaryPath, 0o755);
170
+ }
171
+
172
+ await fsp.rm(archivePath, { force: true });
173
+ await fsp.rm(extractedDir, { recursive: true, force: true });
174
+
175
+ console.log(`qmai 已安装到 ${finalBinaryPath}`);
176
+ }
177
+
178
+ main().catch((error) => {
179
+ fail(`qmai-cli-public 安装失败:${error.message}`);
180
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "qmai-cli-public",
3
+ "version": "0.1.0",
4
+ "description": "qmai-cli npm installer package",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/feixiao629/qmai-cli-public.git"
9
+ },
10
+ "homepage": "https://github.com/feixiao629/qmai-cli-public",
11
+ "bin": {
12
+ "qmai": "npm/bin/qmai.js"
13
+ },
14
+ "files": [
15
+ "README.md",
16
+ "LICENSE",
17
+ "npm",
18
+ ".goreleaser.yml"
19
+ ],
20
+ "scripts": {
21
+ "postinstall": "node npm/install.js"
22
+ },
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "keywords": [
27
+ "qmai",
28
+ "cli",
29
+ "golang"
30
+ ]
31
+ }