siluzan-tso-cli 1.0.0-beta.26 → 1.0.0-beta.28
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/README.md +1 -1
- package/dist/index.js +810 -76
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/finance.md +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
20
20
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
> **注意**:当前为测试版(1.0.0-beta.
|
|
23
|
+
> **注意**:当前为测试版(1.0.0-beta.28),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
24
24
|
|
|
25
25
|
| 助手 | 建议 `--ai` |
|
|
26
26
|
|------|-------------|
|
package/dist/index.js
CHANGED
|
@@ -124,7 +124,15 @@ function rawRequest(url, options) {
|
|
|
124
124
|
res.on("data", (chunk) => {
|
|
125
125
|
data += chunk;
|
|
126
126
|
});
|
|
127
|
-
res.on("end", () =>
|
|
127
|
+
res.on("end", () => {
|
|
128
|
+
const headers = {};
|
|
129
|
+
for (const [key, val] of Object.entries(res.headers)) {
|
|
130
|
+
if (val !== void 0) {
|
|
131
|
+
headers[key.toLowerCase()] = Array.isArray(val) ? val[0] : val;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
resolve2({ status: res.statusCode ?? 0, text: data, headers });
|
|
135
|
+
});
|
|
128
136
|
});
|
|
129
137
|
req.on("error", reject);
|
|
130
138
|
if (options.body) req.write(options.body);
|
|
@@ -588,13 +596,52 @@ async function apiFetch(url, config, options = {}, verbose = false) {
|
|
|
588
596
|
return text;
|
|
589
597
|
}
|
|
590
598
|
}
|
|
599
|
+
async function apiFetchWithHeaders(url, config, options = {}, verbose = false) {
|
|
600
|
+
await prepareSiluzanSentryForApiFetch(url, config, options);
|
|
601
|
+
const method = options.method ?? "GET";
|
|
602
|
+
const authHeaders = config.apiKey ? { "x-api-key": config.apiKey } : { Authorization: `Bearer ${config.authToken}` };
|
|
603
|
+
const reqHeaders = {
|
|
604
|
+
"Content-Type": "application/json",
|
|
605
|
+
"Accept-Language": "zh-CN",
|
|
606
|
+
...authHeaders,
|
|
607
|
+
Datapermission: config.dataPermission ?? "",
|
|
608
|
+
...options.headers ?? {}
|
|
609
|
+
};
|
|
610
|
+
const body = typeof options.body === "string" ? options.body : void 0;
|
|
611
|
+
const res = await rawRequest(url, { method, headers: reqHeaders, body });
|
|
612
|
+
const text = res.text;
|
|
613
|
+
await reportSiluzanApiCall({
|
|
614
|
+
url,
|
|
615
|
+
config,
|
|
616
|
+
method,
|
|
617
|
+
reqHeaders,
|
|
618
|
+
requestBody: body,
|
|
619
|
+
status: res.status,
|
|
620
|
+
responseText: text
|
|
621
|
+
});
|
|
622
|
+
if (res.status < 200 || res.status >= 300) {
|
|
623
|
+
const detail = verbose ? `\uFF1A${redactSensitive(text).slice(0, 300)}` : "";
|
|
624
|
+
throw new Error(`HTTP ${res.status}${detail}`);
|
|
625
|
+
}
|
|
626
|
+
let data;
|
|
627
|
+
if (!text.trim()) {
|
|
628
|
+
data = null;
|
|
629
|
+
} else {
|
|
630
|
+
try {
|
|
631
|
+
data = JSON.parse(text);
|
|
632
|
+
} catch {
|
|
633
|
+
data = text;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return { data, headers: res.headers };
|
|
637
|
+
}
|
|
591
638
|
function sleep(ms) {
|
|
592
639
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
593
640
|
}
|
|
594
641
|
function getCurrentVersion(importMetaUrl) {
|
|
595
642
|
try {
|
|
596
643
|
const __dirname2 = path2.dirname(fileURLToPath(importMetaUrl));
|
|
597
|
-
const pkgPath = path2.join(__dirname2, "..", "
|
|
644
|
+
const pkgPath = path2.join(__dirname2, "..", "package.json");
|
|
598
645
|
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
599
646
|
return pkg.version ?? "0.0.0";
|
|
600
647
|
} catch {
|
|
@@ -809,6 +856,9 @@ function loadConfig(tokenArg) {
|
|
|
809
856
|
function apiFetch2(url, config, options = {}, verbose = false) {
|
|
810
857
|
return apiFetch(url, config, options, verbose);
|
|
811
858
|
}
|
|
859
|
+
function apiFetchWithHeaders2(url, config, options = {}, verbose = false) {
|
|
860
|
+
return apiFetchWithHeaders(url, config, options, verbose);
|
|
861
|
+
}
|
|
812
862
|
|
|
813
863
|
// src/commands/config.ts
|
|
814
864
|
function deriveWebUrl(apiBaseUrl) {
|
|
@@ -1168,6 +1218,81 @@ async function runUpdate(options) {
|
|
|
1168
1218
|
console.log(" \u5982\u679C AI \u52A9\u624B\u6B63\u5728\u8FD0\u884C\uFF0C\u5EFA\u8BAE\u91CD\u542F\u4EE5\u4F7F\u65B0 Skill \u6587\u4EF6\u751F\u6548\u3002\n");
|
|
1169
1219
|
}
|
|
1170
1220
|
|
|
1221
|
+
// src/utils/balance.ts
|
|
1222
|
+
var BALANCE_SUPPORTED_MEDIA = ["Google", "Yandex", "TikTok", "BingV2", "Kwai"];
|
|
1223
|
+
function fmt(d) {
|
|
1224
|
+
return d.toISOString().slice(0, 10);
|
|
1225
|
+
}
|
|
1226
|
+
function defaultDateRange() {
|
|
1227
|
+
const end = /* @__PURE__ */ new Date();
|
|
1228
|
+
const start = /* @__PURE__ */ new Date();
|
|
1229
|
+
start.setDate(start.getDate() - 7);
|
|
1230
|
+
return { startDate: fmt(start), endDate: fmt(end) };
|
|
1231
|
+
}
|
|
1232
|
+
async function fetchBalanceMap(media, accountIds, config, startDate, endDate, verbose) {
|
|
1233
|
+
const result = /* @__PURE__ */ new Map();
|
|
1234
|
+
if (accountIds.length === 0 || media === "MetaAd") return result;
|
|
1235
|
+
try {
|
|
1236
|
+
if (["Google", "Yandex", "TikTok", "BingV2"].includes(media)) {
|
|
1237
|
+
const params = new URLSearchParams({ ids: accountIds.join("|") });
|
|
1238
|
+
const url = `${config.apiBaseUrl}/query/media-account/${media}/GetMediaAccountInfo?${params}`;
|
|
1239
|
+
const raw = await apiFetch2(url, config, {}, verbose);
|
|
1240
|
+
const items = Array.isArray(raw) ? raw : raw.items ?? [];
|
|
1241
|
+
for (const item of items) {
|
|
1242
|
+
if (item.mediaCustomerId != null) {
|
|
1243
|
+
result.set(String(item.mediaCustomerId), item);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
} else if (media === "Kwai") {
|
|
1247
|
+
const range = defaultDateRange();
|
|
1248
|
+
const params = new URLSearchParams({
|
|
1249
|
+
period: "true",
|
|
1250
|
+
startDate: startDate ?? range.startDate,
|
|
1251
|
+
endDate: endDate ?? range.endDate,
|
|
1252
|
+
mediaCustomerIds: accountIds.join(",")
|
|
1253
|
+
});
|
|
1254
|
+
const url = `${config.apiBaseUrl}/report/media-account/Kwai/accountsoverview?${params}`;
|
|
1255
|
+
const raw = await apiFetch2(url, config, {}, verbose);
|
|
1256
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
1257
|
+
for (const item of items) {
|
|
1258
|
+
if (item.mediaAccountId != null) {
|
|
1259
|
+
result.set(String(item.mediaAccountId), {
|
|
1260
|
+
mediaCustomerId: item.mediaAccountId,
|
|
1261
|
+
remainingAccountBudget: item.remainingAccountBudget,
|
|
1262
|
+
status: item.status,
|
|
1263
|
+
currencyCode: item.currencyCode
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
} catch {
|
|
1269
|
+
}
|
|
1270
|
+
return result;
|
|
1271
|
+
}
|
|
1272
|
+
async function fetchOverviewMap(media, accountIds, config, startDate, endDate, verbose) {
|
|
1273
|
+
const result = /* @__PURE__ */ new Map();
|
|
1274
|
+
if (accountIds.length === 0 || media === "MetaAd") return result;
|
|
1275
|
+
const range = defaultDateRange();
|
|
1276
|
+
const params = new URLSearchParams({
|
|
1277
|
+
period: "true",
|
|
1278
|
+
startDate: startDate ?? range.startDate,
|
|
1279
|
+
endDate: endDate ?? range.endDate,
|
|
1280
|
+
mediaCustomerIds: accountIds.join(",")
|
|
1281
|
+
});
|
|
1282
|
+
const url = `${config.apiBaseUrl}/report/media-account/${media}/accountsoverview?${params}`;
|
|
1283
|
+
try {
|
|
1284
|
+
const raw = await apiFetch2(url, config, {}, verbose);
|
|
1285
|
+
const items = Array.isArray(raw) ? raw : [];
|
|
1286
|
+
for (const item of items) {
|
|
1287
|
+
if (item.mediaAccountId != null) {
|
|
1288
|
+
result.set(String(item.mediaAccountId), item);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
} catch {
|
|
1292
|
+
}
|
|
1293
|
+
return result;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1171
1296
|
// src/commands/list-accounts.ts
|
|
1172
1297
|
var VALID_MEDIA_TYPES = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
|
|
1173
1298
|
var PLATFORM_CONFIG = {
|
|
@@ -1226,6 +1351,8 @@ var PLATFORM_CONFIG = {
|
|
|
1226
1351
|
path: "/query/media-account/SearchMediaAcountByCriteria",
|
|
1227
1352
|
pageParam: "pageNum",
|
|
1228
1353
|
fixedParams: {
|
|
1354
|
+
// 与 Meta 同源接口,后端要求 MediaTypes(否则会 400:mediaTypes is required)
|
|
1355
|
+
MediaTypes: "Kwai",
|
|
1229
1356
|
MediaType: "Kwai",
|
|
1230
1357
|
advStatus: "",
|
|
1231
1358
|
mediaAccountState: "Approved,Linked",
|
|
@@ -1235,6 +1362,31 @@ var PLATFORM_CONFIG = {
|
|
|
1235
1362
|
idSearchParam: "mediaCustomerIds"
|
|
1236
1363
|
}
|
|
1237
1364
|
};
|
|
1365
|
+
function mergeTikTokAdList(items, adList) {
|
|
1366
|
+
if (!Array.isArray(adList) || adList.length === 0) return;
|
|
1367
|
+
for (const item of items) {
|
|
1368
|
+
const id = item.ma.mediaCustomerId;
|
|
1369
|
+
if (!id) continue;
|
|
1370
|
+
const ad = adList.find((a) => String(a.mediaCustomerId ?? "") === String(id));
|
|
1371
|
+
if (ad?.status != null) {
|
|
1372
|
+
item.ma.TTADInfo = { status: String(ad.status) };
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
function mergeMetaFacebookAdList(items, adList) {
|
|
1377
|
+
if (!Array.isArray(adList) || adList.length === 0) return;
|
|
1378
|
+
for (const item of items) {
|
|
1379
|
+
const id = item.ma.mediaCustomerId;
|
|
1380
|
+
if (!id) continue;
|
|
1381
|
+
const ad = adList.find((a) => String(a.mediaCustomerId ?? "") === String(id));
|
|
1382
|
+
if (ad) {
|
|
1383
|
+
item.ma.FacebookADInfo = {
|
|
1384
|
+
status: ad.status,
|
|
1385
|
+
reason: ad.reason
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1238
1390
|
async function fetchTikTokAccountByMediaCustomerId(config, mediaCustomerId, verbose) {
|
|
1239
1391
|
const cfg = PLATFORM_CONFIG.TikTok;
|
|
1240
1392
|
const params = new URLSearchParams();
|
|
@@ -1288,7 +1440,10 @@ async function runListAccounts(opts) {
|
|
|
1288
1440
|
const url = `${config.apiBaseUrl}${platformCfg.path}?${params}`;
|
|
1289
1441
|
if (platformCfg.responseType === "array") {
|
|
1290
1442
|
try {
|
|
1291
|
-
|
|
1443
|
+
const res = await apiFetchWithHeaders2(url, config, {}, opts.verbose);
|
|
1444
|
+
items = res.data ?? [];
|
|
1445
|
+
const hit = res.headers["s-total-hits"];
|
|
1446
|
+
if (hit !== void 0) total = parseInt(hit, 10) || void 0;
|
|
1292
1447
|
} catch (err) {
|
|
1293
1448
|
console.error(`
|
|
1294
1449
|
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
@@ -1307,6 +1462,11 @@ async function runListAccounts(opts) {
|
|
|
1307
1462
|
}
|
|
1308
1463
|
items = Array.isArray(res?.mas) ? res.mas : [];
|
|
1309
1464
|
total = typeof res?.total === "number" ? res.total : void 0;
|
|
1465
|
+
if (opts.media === "TikTok") {
|
|
1466
|
+
mergeTikTokAdList(items, res.adList);
|
|
1467
|
+
} else if (opts.media === "MetaAd") {
|
|
1468
|
+
mergeMetaFacebookAdList(items, res.adList);
|
|
1469
|
+
}
|
|
1310
1470
|
}
|
|
1311
1471
|
} else {
|
|
1312
1472
|
const params = new URLSearchParams();
|
|
@@ -1316,7 +1476,10 @@ async function runListAccounts(opts) {
|
|
|
1316
1476
|
params.set("pageSize", String(pageSize));
|
|
1317
1477
|
const url = `${config.apiBaseUrl}/query/media-account/?${params}`;
|
|
1318
1478
|
try {
|
|
1319
|
-
|
|
1479
|
+
const res = await apiFetchWithHeaders2(url, config, {}, opts.verbose);
|
|
1480
|
+
items = res.data ?? [];
|
|
1481
|
+
const hit = res.headers["s-total-hits"];
|
|
1482
|
+
if (hit !== void 0) total = parseInt(hit, 10) || void 0;
|
|
1320
1483
|
} catch (err) {
|
|
1321
1484
|
console.error(`
|
|
1322
1485
|
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
@@ -1324,6 +1487,79 @@ async function runListAccounts(opts) {
|
|
|
1324
1487
|
process.exit(1);
|
|
1325
1488
|
}
|
|
1326
1489
|
}
|
|
1490
|
+
if (items.length > 0) {
|
|
1491
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1492
|
+
for (const item of items) {
|
|
1493
|
+
const id = item.ma.mediaCustomerId;
|
|
1494
|
+
const mediaType = item.ma.mediaAccountType ?? opts.media ?? "";
|
|
1495
|
+
if (id && mediaType) {
|
|
1496
|
+
if (!groups.has(mediaType)) groups.set(mediaType, []);
|
|
1497
|
+
groups.get(mediaType).push(id);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
const diagnoseIdToItem = /* @__PURE__ */ new Map();
|
|
1501
|
+
const aritDiagnoseIds = [];
|
|
1502
|
+
for (const item of items) {
|
|
1503
|
+
for (const report of item.ma.diagnoseReports ?? []) {
|
|
1504
|
+
if (report.reportSource === "ARIT") {
|
|
1505
|
+
diagnoseIdToItem.set(report.websiteDiagnoseId, item);
|
|
1506
|
+
aritDiagnoseIds.push(report.websiteDiagnoseId);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const [balanceMaps, overviewMaps, aritReports] = await Promise.all([
|
|
1511
|
+
// 各媒体类型余额
|
|
1512
|
+
Promise.all(
|
|
1513
|
+
Array.from(groups.entries()).map(
|
|
1514
|
+
([mediaType, ids]) => fetchBalanceMap(mediaType, ids, config, void 0, void 0, opts.verbose)
|
|
1515
|
+
)
|
|
1516
|
+
),
|
|
1517
|
+
// 各媒体类型消耗数据(MetaAd 不支持,fetchOverviewMap 内部会跳过)
|
|
1518
|
+
Promise.all(
|
|
1519
|
+
Array.from(groups.entries()).map(
|
|
1520
|
+
([mediaType, ids]) => fetchOverviewMap(mediaType, ids, config, void 0, void 0, opts.verbose)
|
|
1521
|
+
)
|
|
1522
|
+
),
|
|
1523
|
+
// ARIT 得分
|
|
1524
|
+
aritDiagnoseIds.length > 0 ? apiFetch2(
|
|
1525
|
+
`${config.apiBaseUrl}/query/WebsiteDiagnoseReport/search?ids=${aritDiagnoseIds.join(",")}`,
|
|
1526
|
+
config,
|
|
1527
|
+
{},
|
|
1528
|
+
opts.verbose
|
|
1529
|
+
).catch(() => []) : Promise.resolve([])
|
|
1530
|
+
]);
|
|
1531
|
+
const globalBalance = /* @__PURE__ */ new Map();
|
|
1532
|
+
for (const m of balanceMaps) {
|
|
1533
|
+
for (const [id, info] of m) globalBalance.set(id, info);
|
|
1534
|
+
}
|
|
1535
|
+
const globalOverview = /* @__PURE__ */ new Map();
|
|
1536
|
+
for (const m of overviewMaps) {
|
|
1537
|
+
for (const [id, info] of m) globalOverview.set(id, info);
|
|
1538
|
+
}
|
|
1539
|
+
for (const item of items) {
|
|
1540
|
+
const id = item.ma.mediaCustomerId;
|
|
1541
|
+
if (!id) continue;
|
|
1542
|
+
const balanceInfo = globalBalance.get(id);
|
|
1543
|
+
if (balanceInfo) {
|
|
1544
|
+
item.ma.remainingAccountBudget = balanceInfo.remainingAccountBudget;
|
|
1545
|
+
item.ma.platformStatus = balanceInfo.status ?? balanceInfo.accountStatus;
|
|
1546
|
+
}
|
|
1547
|
+
const overviewInfo = globalOverview.get(id);
|
|
1548
|
+
if (overviewInfo) {
|
|
1549
|
+
item.ma["spend"] = overviewInfo.spend;
|
|
1550
|
+
item.ma["impressions"] = overviewInfo.impressions;
|
|
1551
|
+
item.ma["clicks"] = overviewInfo.clicks;
|
|
1552
|
+
item.ma["conversions"] = overviewInfo.conversions;
|
|
1553
|
+
item.ma["costPerClick"] = overviewInfo.costPerClick;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
for (const report of Array.isArray(aritReports) ? aritReports : []) {
|
|
1557
|
+
const targetItem = diagnoseIdToItem.get(report.websiteDiagnoseId);
|
|
1558
|
+
if (targetItem) {
|
|
1559
|
+
targetItem.ma.aritScore = report.summaryScore ?? "-";
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1327
1563
|
if (opts.json) {
|
|
1328
1564
|
console.log(JSON.stringify(items, null, 2));
|
|
1329
1565
|
return;
|
|
@@ -1336,61 +1572,512 @@ async function runListAccounts(opts) {
|
|
|
1336
1572
|
console.log(`
|
|
1337
1573
|
\u5E7F\u544A\u8D26\u6237\u5217\u8868\uFF08\u7B2C ${page} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761${totalInfo}\uFF09
|
|
1338
1574
|
`);
|
|
1575
|
+
const isGoogle = opts.media === "Google";
|
|
1576
|
+
const isYandex = opts.media === "Yandex";
|
|
1577
|
+
const isTikTok = opts.media === "TikTok";
|
|
1578
|
+
const isMetaAd = opts.media === "MetaAd";
|
|
1579
|
+
const isBingV2 = opts.media === "BingV2";
|
|
1580
|
+
const isKwai = opts.media === "Kwai";
|
|
1581
|
+
if (isGoogle) {
|
|
1582
|
+
printGoogleTable(items);
|
|
1583
|
+
} else if (isYandex) {
|
|
1584
|
+
printYandexTable(items);
|
|
1585
|
+
} else if (isTikTok) {
|
|
1586
|
+
printTikTokTable(items);
|
|
1587
|
+
} else if (isMetaAd) {
|
|
1588
|
+
printMetaTable(items);
|
|
1589
|
+
} else if (isBingV2 || isKwai) {
|
|
1590
|
+
printSpendMetricsAccountTable(items);
|
|
1591
|
+
} else {
|
|
1592
|
+
printDefaultTable(items, opts.media);
|
|
1593
|
+
}
|
|
1594
|
+
const hasMore = total !== void 0 ? page * pageSize < total : items.length >= pageSize;
|
|
1595
|
+
if (hasMore) {
|
|
1596
|
+
console.log(`
|
|
1597
|
+
\u4F7F\u7528 --page <n> \u7FFB\u9875\uFF0C--page-size <n> \u8C03\u6574\u6BCF\u9875\u6570\u91CF\u3002`);
|
|
1598
|
+
}
|
|
1599
|
+
if (isGoogle) {
|
|
1600
|
+
console.log(`
|
|
1601
|
+
\u2139\uFE0F \u6B64\u5217\u8868\u4E0D\u663E\u793A Google \u5C01\u53F7\uFF08Suspended\uFF09\u72B6\u6001\uFF0C\u5982\u9700\u67E5\u770B\u53EF\u63D0\u73B0\u7684\u88AB\u5C01\u8D26\u6237\u8BF7\u8FD0\u884C\uFF1A`);
|
|
1602
|
+
console.log(` siluzan-tso account withdraw-list`);
|
|
1603
|
+
}
|
|
1604
|
+
console.log();
|
|
1605
|
+
}
|
|
1606
|
+
function fmtNum(v, decimals = 2) {
|
|
1607
|
+
const n = Number(v);
|
|
1608
|
+
return isNaN(n) ? "-" : n.toFixed(decimals);
|
|
1609
|
+
}
|
|
1610
|
+
function fmtDate(v) {
|
|
1611
|
+
if (!v) return "-";
|
|
1612
|
+
return v.slice(0, 10);
|
|
1613
|
+
}
|
|
1614
|
+
function formatTikTokAuditStatus(ma) {
|
|
1615
|
+
const state = ma.mediaAccountState ?? "";
|
|
1616
|
+
const tt = ma.TTADInfo?.status ?? "";
|
|
1617
|
+
if (state === "Created") return "\u5BA1\u6838\u4E2D";
|
|
1618
|
+
if (state === "Denied") return "\u5DF2\u62D2\u7EDD";
|
|
1619
|
+
if (state === "Approved" || state === "Linked") {
|
|
1620
|
+
if (tt === "STATUS_ENABLE") return "\u6B63\u5E38\u542F\u7528";
|
|
1621
|
+
if (tt === "STATUS_LIMIT") return "\u9650\u5236\u6295\u653E";
|
|
1622
|
+
if (tt === "STATUS_DISABLE") return "\u5DF2\u7981\u7528";
|
|
1623
|
+
if (tt) return tt;
|
|
1624
|
+
if (state === "Approved") return "\u4EBA\u5DE5\u5BA1\u6838\u6210\u529F";
|
|
1625
|
+
if (state === "Linked") return "\u5DF2\u5173\u8054";
|
|
1626
|
+
}
|
|
1627
|
+
return state || "-";
|
|
1628
|
+
}
|
|
1629
|
+
function formatTikTokBcColumn(ma) {
|
|
1630
|
+
const infos = ma.bcInfos;
|
|
1631
|
+
if (!Array.isArray(infos) || infos.length === 0) return "-";
|
|
1632
|
+
const first = infos[0];
|
|
1633
|
+
const id = String(first?.bcId ?? first?.bc_id ?? "").trim();
|
|
1634
|
+
const primary = id || "\u2014";
|
|
1635
|
+
if (infos.length <= 1) return primary;
|
|
1636
|
+
return `${primary}(+${infos.length - 1})`;
|
|
1637
|
+
}
|
|
1638
|
+
function displayMetaAccountId(id) {
|
|
1639
|
+
if (id == null || id === "") return "(\u672A\u5F00\u901A)";
|
|
1640
|
+
const s = String(id);
|
|
1641
|
+
return s.startsWith("act_") ? s.slice(4) : s;
|
|
1642
|
+
}
|
|
1643
|
+
function formatMetaAuthType(mediaAccountType) {
|
|
1644
|
+
if (mediaAccountType === "MetaAd") return "Meta \u8D26\u6237";
|
|
1645
|
+
if (mediaAccountType === "FacebookAds") return "Facebook \u5E7F\u544A\u8D26\u6237";
|
|
1646
|
+
return mediaAccountType ?? "-";
|
|
1647
|
+
}
|
|
1648
|
+
function formatMetaOAuthColumn(ma) {
|
|
1649
|
+
return ma.invalidOAuthToken ? "\u5931\u6548" : "\u6B63\u5E38";
|
|
1650
|
+
}
|
|
1651
|
+
function formatMetaAuditStatus(ma) {
|
|
1652
|
+
const ms = ma.mediaAccountState ?? "";
|
|
1653
|
+
if (ms !== "Approved" && ms !== "Linked") {
|
|
1654
|
+
return "\u672A\u77E5\u72B6\u6001";
|
|
1655
|
+
}
|
|
1656
|
+
const raw = ma.FacebookADInfo?.status;
|
|
1657
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
1658
|
+
return "\u672A\u77E5\u72B6\u6001";
|
|
1659
|
+
}
|
|
1660
|
+
if (typeof raw === "number") {
|
|
1661
|
+
const numMap = {
|
|
1662
|
+
1: "\u6D3B\u8DC3",
|
|
1663
|
+
2: "\u5DF2\u7981\u7528",
|
|
1664
|
+
3: "\u672A\u7ED3\u6E05",
|
|
1665
|
+
7: "\u5F85\u98CE\u63A7\u5BA1\u6838",
|
|
1666
|
+
8: "\u4F59\u989D\u5DF2\u6E05\u96F6",
|
|
1667
|
+
9: "\u5DF2\u5173\u95ED",
|
|
1668
|
+
100: "\u5F85\u4ED8\u6B3E",
|
|
1669
|
+
101: "\u5DF2\u5173\u95ED",
|
|
1670
|
+
201: "\u4EFB\u4F55",
|
|
1671
|
+
202: "\u5DF2\u5173\u95ED"
|
|
1672
|
+
};
|
|
1673
|
+
return numMap[raw] ?? `\u72B6\u6001\u7801 ${raw}`;
|
|
1674
|
+
}
|
|
1675
|
+
const u = String(raw).toUpperCase();
|
|
1676
|
+
const strMap = {
|
|
1677
|
+
ACTIVE: "\u6D3B\u8DC3",
|
|
1678
|
+
DISABLED: "\u5DF2\u505C\u7528",
|
|
1679
|
+
UNSETTLED: "\u672A\u7ED3\u6E05",
|
|
1680
|
+
PENDING_RISK_REVIEW: "\u98CE\u63A7\u5BA1\u6838\u4E2D",
|
|
1681
|
+
PENDING_SETTLEMENT: "\u5F85\u7ED3\u7B97",
|
|
1682
|
+
IN_GRACE_PERIOD: "\u5BBD\u9650\u671F",
|
|
1683
|
+
PENDING_CLOSURE: "\u5F85\u5173\u95ED",
|
|
1684
|
+
CLOSED: "\u5DF2\u5173\u95ED",
|
|
1685
|
+
ANY: "\u4EFB\u4F55"
|
|
1686
|
+
};
|
|
1687
|
+
return strMap[u] ?? String(raw);
|
|
1688
|
+
}
|
|
1689
|
+
function printMetaTable(items) {
|
|
1690
|
+
const rows = items.map((item) => {
|
|
1691
|
+
const ma = item.ma;
|
|
1692
|
+
return {
|
|
1693
|
+
company: item.mag?.advertiserName ?? "-",
|
|
1694
|
+
id: displayMetaAccountId(ma.mediaCustomerId),
|
|
1695
|
+
name: ma.mediaCustomerName ?? "-",
|
|
1696
|
+
oauthState: formatMetaOAuthColumn(ma),
|
|
1697
|
+
auditState: formatMetaAuditStatus(ma),
|
|
1698
|
+
authType: formatMetaAuthType(ma.mediaAccountType),
|
|
1699
|
+
createdAt: fmtDate(ma.createdDateTime)
|
|
1700
|
+
};
|
|
1701
|
+
});
|
|
1702
|
+
const cw = {
|
|
1703
|
+
company: Math.max(8, ...rows.map((r) => r.company.length)),
|
|
1704
|
+
id: Math.max(10, ...rows.map((r) => r.id.length)),
|
|
1705
|
+
name: Math.max(8, ...rows.map((r) => r.name.length)),
|
|
1706
|
+
oauthState: Math.max(4, ...rows.map((r) => r.oauthState.length)),
|
|
1707
|
+
auditState: Math.max(8, ...rows.map((r) => r.auditState.length)),
|
|
1708
|
+
authType: Math.max(12, ...rows.map((r) => r.authType.length)),
|
|
1709
|
+
createdAt: 12
|
|
1710
|
+
};
|
|
1711
|
+
const sep = " ";
|
|
1712
|
+
const header = [
|
|
1713
|
+
"\u516C\u53F8\u540D\u79F0".padEnd(cw.company),
|
|
1714
|
+
"\u8D26\u6237ID".padEnd(cw.id),
|
|
1715
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
1716
|
+
"\u72B6\u6001".padEnd(cw.oauthState),
|
|
1717
|
+
"\u5BA1\u6838\u72B6\u6001".padEnd(cw.auditState),
|
|
1718
|
+
"\u6388\u6743\u7C7B\u578B".padEnd(cw.authType),
|
|
1719
|
+
"\u6388\u6743/\u5F00\u6237\u65F6\u95F4".padEnd(cw.createdAt)
|
|
1720
|
+
].join(sep);
|
|
1721
|
+
console.log(" " + header);
|
|
1722
|
+
console.log(" " + "-".repeat(header.length));
|
|
1723
|
+
for (const r of rows) {
|
|
1724
|
+
console.log(" " + [
|
|
1725
|
+
r.company.padEnd(cw.company),
|
|
1726
|
+
r.id.padEnd(cw.id),
|
|
1727
|
+
r.name.padEnd(cw.name),
|
|
1728
|
+
r.oauthState.padEnd(cw.oauthState),
|
|
1729
|
+
r.auditState.padEnd(cw.auditState),
|
|
1730
|
+
r.authType.padEnd(cw.authType),
|
|
1731
|
+
r.createdAt.padEnd(cw.createdAt)
|
|
1732
|
+
].join(sep));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
function printSpendMetricsAccountTable(items) {
|
|
1339
1736
|
const rows = items.map((item) => {
|
|
1340
1737
|
const ma = item.ma;
|
|
1341
|
-
|
|
1738
|
+
const authStatus = ma.invalidOAuthToken ? "\u26A0\uFE0F \u5931\u6548" : "\u2705 \u6B63\u5E38";
|
|
1739
|
+
const balance = ma.remainingAccountBudget != null ? `${ma.currencyCode ?? ""} ${ma.remainingAccountBudget.toFixed(2)}`.trim() : "-";
|
|
1740
|
+
const sharedCount = Array.isArray(ma.accountIds) ? String(Math.max(0, ma.accountIds.length - 1)) : "-";
|
|
1741
|
+
return {
|
|
1742
|
+
company: item.mag?.advertiserName ?? "-",
|
|
1743
|
+
id: ma.mediaCustomerId != null && String(ma.mediaCustomerId).trim() !== "" ? String(ma.mediaCustomerId) : "(\u672A\u5F00\u901A)",
|
|
1744
|
+
name: ma.mediaCustomerName ?? "-",
|
|
1745
|
+
spend: fmtNum(ma["spend"]),
|
|
1746
|
+
impressions: fmtNum(ma["impressions"], 0),
|
|
1747
|
+
conversions: fmtNum(ma["conversions"], 0),
|
|
1748
|
+
clicks: fmtNum(ma["clicks"], 0),
|
|
1749
|
+
cpc: fmtNum(ma["costPerClick"]),
|
|
1750
|
+
balance,
|
|
1751
|
+
authStatus,
|
|
1752
|
+
createdAt: fmtDate(ma.createdDateTime),
|
|
1753
|
+
shared: sharedCount
|
|
1754
|
+
};
|
|
1755
|
+
});
|
|
1756
|
+
const cw = {
|
|
1757
|
+
company: Math.max(8, ...rows.map((r) => r.company.length)),
|
|
1758
|
+
id: Math.max(10, ...rows.map((r) => r.id.length)),
|
|
1759
|
+
name: Math.max(8, ...rows.map((r) => r.name.length)),
|
|
1760
|
+
spend: Math.max(6, ...rows.map((r) => r.spend.length)),
|
|
1761
|
+
impressions: Math.max(8, ...rows.map((r) => r.impressions.length)),
|
|
1762
|
+
conversions: Math.max(8, ...rows.map((r) => r.conversions.length)),
|
|
1763
|
+
clicks: Math.max(8, ...rows.map((r) => r.clicks.length)),
|
|
1764
|
+
cpc: Math.max(8, ...rows.map((r) => r.cpc.length)),
|
|
1765
|
+
balance: Math.max(8, ...rows.map((r) => r.balance.length)),
|
|
1766
|
+
authStatus: Math.max(6, ...rows.map((r) => r.authStatus.length)),
|
|
1767
|
+
createdAt: 12,
|
|
1768
|
+
shared: 6
|
|
1769
|
+
};
|
|
1770
|
+
const sep = " ";
|
|
1771
|
+
const header = [
|
|
1772
|
+
"\u516C\u53F8\u540D\u79F0".padEnd(cw.company),
|
|
1773
|
+
"\u8D26\u6237ID".padEnd(cw.id),
|
|
1774
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
1775
|
+
"\u6D88\u8017".padEnd(cw.spend),
|
|
1776
|
+
"\u5C55\u793A\u6B21\u6570".padEnd(cw.impressions),
|
|
1777
|
+
"\u8F6C\u5316\u6B21\u6570".padEnd(cw.conversions),
|
|
1778
|
+
"\u70B9\u51FB\u6B21\u6570".padEnd(cw.clicks),
|
|
1779
|
+
"\u70B9\u51FB\u5747\u4EF7".padEnd(cw.cpc),
|
|
1780
|
+
"\u4F59\u989D".padEnd(cw.balance),
|
|
1781
|
+
"\u6388\u6743\u72B6\u6001".padEnd(cw.authStatus),
|
|
1782
|
+
"\u6388\u6743/\u5F00\u6237\u65F6\u95F4".padEnd(cw.createdAt),
|
|
1783
|
+
"\u5206\u4EAB\u8D26\u6237".padEnd(cw.shared)
|
|
1784
|
+
].join(sep);
|
|
1785
|
+
console.log(" " + header);
|
|
1786
|
+
console.log(" " + "-".repeat(header.length));
|
|
1787
|
+
for (const r of rows) {
|
|
1788
|
+
console.log(" " + [
|
|
1789
|
+
r.company.padEnd(cw.company),
|
|
1790
|
+
r.id.padEnd(cw.id),
|
|
1791
|
+
r.name.padEnd(cw.name),
|
|
1792
|
+
r.spend.padEnd(cw.spend),
|
|
1793
|
+
r.impressions.padEnd(cw.impressions),
|
|
1794
|
+
r.conversions.padEnd(cw.conversions),
|
|
1795
|
+
r.clicks.padEnd(cw.clicks),
|
|
1796
|
+
r.cpc.padEnd(cw.cpc),
|
|
1797
|
+
r.balance.padEnd(cw.balance),
|
|
1798
|
+
r.authStatus.padEnd(cw.authStatus),
|
|
1799
|
+
r.createdAt.padEnd(cw.createdAt),
|
|
1800
|
+
r.shared.padEnd(cw.shared)
|
|
1801
|
+
].join(sep));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
function printYandexTable(items) {
|
|
1805
|
+
const rows = items.map((item) => {
|
|
1806
|
+
const ma = item.ma;
|
|
1807
|
+
const authStatus = ma.invalidOAuthToken ? "\u26A0\uFE0F \u5931\u6548" : "\u2705 \u6B63\u5E38";
|
|
1808
|
+
const balance = ma.remainingAccountBudget != null ? `${ma.currencyCode ?? ""} ${ma.remainingAccountBudget.toFixed(2)}`.trim() : "-";
|
|
1809
|
+
const sharedCount = Array.isArray(ma.accountIds) ? String(Math.max(0, ma.accountIds.length - 1)) : "-";
|
|
1810
|
+
const pwd = ma.mediaPassword != null && String(ma.mediaPassword).trim() !== "" ? String(ma.mediaPassword) : "-";
|
|
1811
|
+
return {
|
|
1812
|
+
company: item.mag?.advertiserName ?? "-",
|
|
1813
|
+
firstPwd: pwd,
|
|
1814
|
+
name: ma.mediaCustomerName ?? "-",
|
|
1815
|
+
spend: fmtNum(ma["spend"]),
|
|
1816
|
+
impressions: fmtNum(ma["impressions"], 0),
|
|
1817
|
+
conversions: fmtNum(ma["conversions"], 0),
|
|
1818
|
+
clicks: fmtNum(ma["clicks"], 0),
|
|
1819
|
+
cpc: fmtNum(ma["costPerClick"]),
|
|
1820
|
+
balance,
|
|
1821
|
+
authStatus,
|
|
1822
|
+
createdAt: fmtDate(ma.createdDateTime),
|
|
1823
|
+
shared: sharedCount
|
|
1824
|
+
};
|
|
1825
|
+
});
|
|
1826
|
+
const cw = {
|
|
1827
|
+
company: Math.max(8, ...rows.map((r) => r.company.length)),
|
|
1828
|
+
firstPwd: Math.max(12, ...rows.map((r) => r.firstPwd.length)),
|
|
1829
|
+
name: Math.max(8, ...rows.map((r) => r.name.length)),
|
|
1830
|
+
spend: Math.max(6, ...rows.map((r) => r.spend.length)),
|
|
1831
|
+
impressions: Math.max(8, ...rows.map((r) => r.impressions.length)),
|
|
1832
|
+
conversions: Math.max(8, ...rows.map((r) => r.conversions.length)),
|
|
1833
|
+
clicks: Math.max(8, ...rows.map((r) => r.clicks.length)),
|
|
1834
|
+
cpc: Math.max(8, ...rows.map((r) => r.cpc.length)),
|
|
1835
|
+
balance: Math.max(8, ...rows.map((r) => r.balance.length)),
|
|
1836
|
+
authStatus: Math.max(6, ...rows.map((r) => r.authStatus.length)),
|
|
1837
|
+
createdAt: 12,
|
|
1838
|
+
shared: 6
|
|
1839
|
+
};
|
|
1840
|
+
const sep = " ";
|
|
1841
|
+
const header = [
|
|
1842
|
+
"\u516C\u53F8\u540D\u79F0".padEnd(cw.company),
|
|
1843
|
+
"\u9996\u6B21\u767B\u9646\u5BC6\u7801".padEnd(cw.firstPwd),
|
|
1844
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
1845
|
+
"\u6D88\u8017".padEnd(cw.spend),
|
|
1846
|
+
"\u5C55\u793A\u6B21\u6570".padEnd(cw.impressions),
|
|
1847
|
+
"\u8F6C\u5316\u6B21\u6570".padEnd(cw.conversions),
|
|
1848
|
+
"\u70B9\u51FB\u6B21\u6570".padEnd(cw.clicks),
|
|
1849
|
+
"\u70B9\u51FB\u5747\u4EF7".padEnd(cw.cpc),
|
|
1850
|
+
"\u4F59\u989D".padEnd(cw.balance),
|
|
1851
|
+
"\u6388\u6743\u72B6\u6001".padEnd(cw.authStatus),
|
|
1852
|
+
"\u6388\u6743/\u5F00\u6237\u65F6\u95F4".padEnd(cw.createdAt),
|
|
1853
|
+
"\u5206\u4EAB\u8D26\u6237".padEnd(cw.shared)
|
|
1854
|
+
].join(sep);
|
|
1855
|
+
console.log(" " + header);
|
|
1856
|
+
console.log(" " + "-".repeat(header.length));
|
|
1857
|
+
for (const r of rows) {
|
|
1858
|
+
console.log(" " + [
|
|
1859
|
+
r.company.padEnd(cw.company),
|
|
1860
|
+
r.firstPwd.padEnd(cw.firstPwd),
|
|
1861
|
+
r.name.padEnd(cw.name),
|
|
1862
|
+
r.spend.padEnd(cw.spend),
|
|
1863
|
+
r.impressions.padEnd(cw.impressions),
|
|
1864
|
+
r.conversions.padEnd(cw.conversions),
|
|
1865
|
+
r.clicks.padEnd(cw.clicks),
|
|
1866
|
+
r.cpc.padEnd(cw.cpc),
|
|
1867
|
+
r.balance.padEnd(cw.balance),
|
|
1868
|
+
r.authStatus.padEnd(cw.authStatus),
|
|
1869
|
+
r.createdAt.padEnd(cw.createdAt),
|
|
1870
|
+
r.shared.padEnd(cw.shared)
|
|
1871
|
+
].join(sep));
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
function printTikTokTable(items) {
|
|
1875
|
+
const rows = items.map((item) => {
|
|
1876
|
+
const ma = item.ma;
|
|
1877
|
+
const authStatus = ma.invalidOAuthToken ? "\u26A0\uFE0F \u5931\u6548" : "\u2705 \u6B63\u5E38";
|
|
1878
|
+
const balance = ma.remainingAccountBudget != null ? `${ma.currencyCode ?? ""} ${ma.remainingAccountBudget.toFixed(2)}`.trim() : "-";
|
|
1879
|
+
const sharedCount = Array.isArray(ma.accountIds) ? String(Math.max(0, ma.accountIds.length - 1)) : "-";
|
|
1880
|
+
return {
|
|
1881
|
+
company: item.mag?.advertiserName ?? "-",
|
|
1882
|
+
id: ma.mediaCustomerId ?? "(\u672A\u5F00\u901A)",
|
|
1883
|
+
name: ma.mediaCustomerName ?? "-",
|
|
1884
|
+
spend: fmtNum(ma["spend"]),
|
|
1885
|
+
impressions: fmtNum(ma["impressions"], 0),
|
|
1886
|
+
conversions: fmtNum(ma["conversions"], 0),
|
|
1887
|
+
clicks: fmtNum(ma["clicks"], 0),
|
|
1888
|
+
cpc: fmtNum(ma["costPerClick"]),
|
|
1889
|
+
balance,
|
|
1890
|
+
bc: formatTikTokBcColumn(ma),
|
|
1891
|
+
authStatus,
|
|
1892
|
+
auditStatus: formatTikTokAuditStatus(ma),
|
|
1893
|
+
createdAt: fmtDate(ma.createdDateTime),
|
|
1894
|
+
shared: sharedCount
|
|
1895
|
+
};
|
|
1896
|
+
});
|
|
1897
|
+
const cw = {
|
|
1898
|
+
company: Math.max(8, ...rows.map((r) => r.company.length)),
|
|
1899
|
+
id: Math.max(10, ...rows.map((r) => r.id.length)),
|
|
1900
|
+
name: Math.max(8, ...rows.map((r) => r.name.length)),
|
|
1901
|
+
spend: Math.max(6, ...rows.map((r) => r.spend.length)),
|
|
1902
|
+
impressions: Math.max(8, ...rows.map((r) => r.impressions.length)),
|
|
1903
|
+
conversions: Math.max(8, ...rows.map((r) => r.conversions.length)),
|
|
1904
|
+
clicks: Math.max(8, ...rows.map((r) => r.clicks.length)),
|
|
1905
|
+
cpc: Math.max(8, ...rows.map((r) => r.cpc.length)),
|
|
1906
|
+
balance: Math.max(8, ...rows.map((r) => r.balance.length)),
|
|
1907
|
+
bc: Math.max(4, ...rows.map((r) => r.bc.length)),
|
|
1908
|
+
authStatus: Math.max(6, ...rows.map((r) => r.authStatus.length)),
|
|
1909
|
+
auditStatus: Math.max(8, ...rows.map((r) => r.auditStatus.length)),
|
|
1910
|
+
createdAt: 12,
|
|
1911
|
+
shared: 6
|
|
1912
|
+
};
|
|
1913
|
+
const sep = " ";
|
|
1914
|
+
const header = [
|
|
1915
|
+
"\u516C\u53F8\u540D\u79F0".padEnd(cw.company),
|
|
1916
|
+
"\u8D26\u6237ID".padEnd(cw.id),
|
|
1917
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
1918
|
+
"\u6D88\u8017".padEnd(cw.spend),
|
|
1919
|
+
"\u5C55\u793A\u6B21\u6570".padEnd(cw.impressions),
|
|
1920
|
+
"\u8F6C\u5316\u6B21\u6570".padEnd(cw.conversions),
|
|
1921
|
+
"\u70B9\u51FB\u6B21\u6570".padEnd(cw.clicks),
|
|
1922
|
+
"\u70B9\u51FB\u5747\u4EF7".padEnd(cw.cpc),
|
|
1923
|
+
"\u4F59\u989D".padEnd(cw.balance),
|
|
1924
|
+
"BC".padEnd(cw.bc),
|
|
1925
|
+
"\u6388\u6743\u72B6\u6001".padEnd(cw.authStatus),
|
|
1926
|
+
"\u5BA1\u6838\u72B6\u6001".padEnd(cw.auditStatus),
|
|
1927
|
+
"\u6388\u6743/\u5F00\u6237\u65F6\u95F4".padEnd(cw.createdAt),
|
|
1928
|
+
"\u5206\u4EAB\u8D26\u6237".padEnd(cw.shared)
|
|
1929
|
+
].join(sep);
|
|
1930
|
+
console.log(" " + header);
|
|
1931
|
+
console.log(" " + "-".repeat(header.length));
|
|
1932
|
+
for (const r of rows) {
|
|
1933
|
+
console.log(" " + [
|
|
1934
|
+
r.company.padEnd(cw.company),
|
|
1935
|
+
String(r.id).padEnd(cw.id),
|
|
1936
|
+
r.name.padEnd(cw.name),
|
|
1937
|
+
r.spend.padEnd(cw.spend),
|
|
1938
|
+
r.impressions.padEnd(cw.impressions),
|
|
1939
|
+
r.conversions.padEnd(cw.conversions),
|
|
1940
|
+
r.clicks.padEnd(cw.clicks),
|
|
1941
|
+
r.cpc.padEnd(cw.cpc),
|
|
1942
|
+
r.balance.padEnd(cw.balance),
|
|
1943
|
+
r.bc.padEnd(cw.bc),
|
|
1944
|
+
r.authStatus.padEnd(cw.authStatus),
|
|
1945
|
+
r.auditStatus.padEnd(cw.auditStatus),
|
|
1946
|
+
r.createdAt.padEnd(cw.createdAt),
|
|
1947
|
+
r.shared.padEnd(cw.shared)
|
|
1948
|
+
].join(sep));
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
function printGoogleTable(items) {
|
|
1952
|
+
const rows = items.map((item) => {
|
|
1953
|
+
const ma = item.ma;
|
|
1954
|
+
const authStatus = ma.invalidOAuthToken ? "\u26A0\uFE0F \u5931\u6548" : "\u2705 \u6B63\u5E38";
|
|
1955
|
+
const platformStatus = ma.platformStatus ?? "-";
|
|
1956
|
+
const balance = ma.remainingAccountBudget != null ? `${ma.currencyCode ?? ""} ${ma.remainingAccountBudget.toFixed(2)}`.trim() : "-";
|
|
1957
|
+
const sharedCount = Array.isArray(ma.accountIds) ? String(Math.max(0, ma.accountIds.length - 1)) : "-";
|
|
1958
|
+
return {
|
|
1959
|
+
company: item.mag?.advertiserName ?? "-",
|
|
1960
|
+
id: ma.mediaCustomerId ?? "(\u672A\u5F00\u901A)",
|
|
1961
|
+
name: ma.mediaCustomerName ?? "-",
|
|
1962
|
+
spend: fmtNum(ma["spend"]),
|
|
1963
|
+
impressions: fmtNum(ma["impressions"], 0),
|
|
1964
|
+
conversions: fmtNum(ma["conversions"], 0),
|
|
1965
|
+
clicks: fmtNum(ma["clicks"], 0),
|
|
1966
|
+
cpc: fmtNum(ma["costPerClick"]),
|
|
1967
|
+
balance,
|
|
1968
|
+
arit: String(ma.aritScore ?? "-"),
|
|
1969
|
+
platformStatus,
|
|
1970
|
+
authStatus,
|
|
1971
|
+
createdAt: fmtDate(ma.createdDateTime),
|
|
1972
|
+
shared: sharedCount
|
|
1973
|
+
};
|
|
1974
|
+
});
|
|
1975
|
+
const cw = {
|
|
1976
|
+
company: Math.max(8, ...rows.map((r) => r.company.length)),
|
|
1977
|
+
id: Math.max(10, ...rows.map((r) => r.id.length)),
|
|
1978
|
+
name: Math.max(8, ...rows.map((r) => r.name.length)),
|
|
1979
|
+
spend: Math.max(6, ...rows.map((r) => r.spend.length)),
|
|
1980
|
+
impressions: Math.max(6, ...rows.map((r) => r.impressions.length)),
|
|
1981
|
+
conversions: Math.max(6, ...rows.map((r) => r.conversions.length)),
|
|
1982
|
+
clicks: Math.max(6, ...rows.map((r) => r.clicks.length)),
|
|
1983
|
+
cpc: Math.max(6, ...rows.map((r) => r.cpc.length)),
|
|
1984
|
+
balance: Math.max(8, ...rows.map((r) => r.balance.length)),
|
|
1985
|
+
arit: Math.max(6, ...rows.map((r) => r.arit.length)),
|
|
1986
|
+
platformStatus: Math.max(6, ...rows.map((r) => r.platformStatus.length)),
|
|
1987
|
+
authStatus: Math.max(6, ...rows.map((r) => r.authStatus.length)),
|
|
1988
|
+
createdAt: 10,
|
|
1989
|
+
shared: 4
|
|
1990
|
+
};
|
|
1991
|
+
const sep = " ";
|
|
1992
|
+
const header = [
|
|
1993
|
+
"\u516C\u53F8\u540D\u79F0".padEnd(cw.company),
|
|
1994
|
+
"\u8D26\u6237ID".padEnd(cw.id),
|
|
1995
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
1996
|
+
"\u6D88\u8017".padEnd(cw.spend),
|
|
1997
|
+
"\u5C55\u793A".padEnd(cw.impressions),
|
|
1998
|
+
"\u8F6C\u5316".padEnd(cw.conversions),
|
|
1999
|
+
"\u70B9\u51FB".padEnd(cw.clicks),
|
|
2000
|
+
"\u70B9\u51FB\u5747\u4EF7".padEnd(cw.cpc),
|
|
2001
|
+
"\u4F59\u989D".padEnd(cw.balance),
|
|
2002
|
+
"Arit".padEnd(cw.arit),
|
|
2003
|
+
"\u8D26\u6237\u72B6\u6001".padEnd(cw.platformStatus),
|
|
2004
|
+
"\u6388\u6743\u72B6\u6001".padEnd(cw.authStatus),
|
|
2005
|
+
"\u6388\u6743/\u5F00\u6237\u65F6\u95F4".padEnd(cw.createdAt),
|
|
2006
|
+
"\u5206\u4EAB"
|
|
2007
|
+
].join(sep);
|
|
2008
|
+
console.log(" " + header);
|
|
2009
|
+
console.log(" " + "-".repeat(header.length));
|
|
2010
|
+
for (const r of rows) {
|
|
2011
|
+
const line = [
|
|
2012
|
+
r.company.padEnd(cw.company),
|
|
2013
|
+
r.id.padEnd(cw.id),
|
|
2014
|
+
r.name.padEnd(cw.name),
|
|
2015
|
+
r.spend.padEnd(cw.spend),
|
|
2016
|
+
r.impressions.padEnd(cw.impressions),
|
|
2017
|
+
r.conversions.padEnd(cw.conversions),
|
|
2018
|
+
r.clicks.padEnd(cw.clicks),
|
|
2019
|
+
r.cpc.padEnd(cw.cpc),
|
|
2020
|
+
r.balance.padEnd(cw.balance),
|
|
2021
|
+
r.arit.padEnd(cw.arit),
|
|
2022
|
+
r.platformStatus.padEnd(cw.platformStatus),
|
|
2023
|
+
r.authStatus.padEnd(cw.authStatus),
|
|
2024
|
+
r.createdAt.padEnd(cw.createdAt),
|
|
2025
|
+
r.shared
|
|
2026
|
+
].join(sep);
|
|
2027
|
+
console.log(" " + line);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
function printDefaultTable(items, media) {
|
|
2031
|
+
const rows = items.map((item) => {
|
|
2032
|
+
const ma = item.ma;
|
|
2033
|
+
let statusLabel;
|
|
1342
2034
|
if (ma.disabled) {
|
|
1343
|
-
|
|
2035
|
+
statusLabel = "\u{1F6AB} \u5DF2\u7981\u7528";
|
|
1344
2036
|
} else if (!ma.mediaCustomerId) {
|
|
1345
|
-
|
|
2037
|
+
statusLabel = "\u23F3 \u672A\u5F00\u901A";
|
|
1346
2038
|
} else if (ma.invalidOAuthToken) {
|
|
1347
|
-
|
|
2039
|
+
statusLabel = "\u26A0\uFE0F OAuth\u5931\u6548";
|
|
1348
2040
|
} else {
|
|
1349
|
-
|
|
2041
|
+
statusLabel = "\u2705 \u6B63\u5E38";
|
|
1350
2042
|
}
|
|
2043
|
+
const balance = ma.remainingAccountBudget != null ? `${ma.currencyCode ?? ""} ${ma.remainingAccountBudget.toFixed(2)}`.trim() : "-";
|
|
1351
2044
|
return {
|
|
1352
2045
|
mediaType: ma.mediaAccountType ?? "",
|
|
1353
2046
|
mediaCustomerId: ma.mediaCustomerId ?? "(\u672A\u5F00\u901A)",
|
|
1354
2047
|
advertiserName: item.mag?.advertiserName ?? "",
|
|
1355
2048
|
mediaCustomerName: ma.mediaCustomerName ?? "",
|
|
1356
|
-
|
|
2049
|
+
balance,
|
|
2050
|
+
status: statusLabel
|
|
1357
2051
|
};
|
|
1358
2052
|
});
|
|
1359
|
-
const
|
|
2053
|
+
const cw = {
|
|
1360
2054
|
mediaType: Math.max(8, ...rows.map((r) => r.mediaType.length)),
|
|
1361
2055
|
mediaCustomerId: Math.max(10, ...rows.map((r) => r.mediaCustomerId.length)),
|
|
1362
2056
|
advertiserName: Math.max(8, ...rows.map((r) => r.advertiserName.length)),
|
|
1363
|
-
name: Math.max(8, ...rows.map((r) => r.mediaCustomerName.length))
|
|
2057
|
+
name: Math.max(8, ...rows.map((r) => r.mediaCustomerName.length)),
|
|
2058
|
+
balance: Math.max(8, ...rows.map((r) => r.balance.length))
|
|
1364
2059
|
};
|
|
1365
2060
|
const header = [
|
|
1366
|
-
"\u5A92\u4F53\u7C7B\u578B".padEnd(
|
|
1367
|
-
"\u8D26\u6237ID".padEnd(
|
|
1368
|
-
"\u5E7F\u544A\u4E3B".padEnd(
|
|
1369
|
-
"\u8D26\u6237\u540D\u79F0".padEnd(
|
|
2061
|
+
media ? "" : "\u5A92\u4F53\u7C7B\u578B".padEnd(cw.mediaType),
|
|
2062
|
+
"\u8D26\u6237ID".padEnd(cw.mediaCustomerId),
|
|
2063
|
+
"\u5E7F\u544A\u4E3B".padEnd(cw.advertiserName),
|
|
2064
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
2065
|
+
"\u4F59\u989D".padEnd(cw.balance),
|
|
1370
2066
|
"\u8D26\u6237\u72B6\u6001"
|
|
1371
|
-
].join(" ");
|
|
2067
|
+
].filter(Boolean).join(" ");
|
|
1372
2068
|
console.log(" " + header);
|
|
1373
2069
|
console.log(" " + "-".repeat(header.length));
|
|
1374
|
-
for (const
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
if (hasMore) {
|
|
1385
|
-
console.log(`
|
|
1386
|
-
\u4F7F\u7528 --page <n> \u7FFB\u9875\uFF0C--page-size <n> \u8C03\u6574\u6BCF\u9875\u6570\u91CF\u3002`);
|
|
1387
|
-
}
|
|
1388
|
-
if (opts.media === "Google") {
|
|
1389
|
-
console.log(`
|
|
1390
|
-
\u2139\uFE0F \u6B64\u5217\u8868\u4E0D\u663E\u793A Google \u5C01\u53F7\uFF08Suspended\uFF09\u72B6\u6001\uFF0C\u5982\u9700\u67E5\u770B\u53EF\u63D0\u73B0\u7684\u88AB\u5C01\u8D26\u6237\u8BF7\u8FD0\u884C\uFF1A`);
|
|
1391
|
-
console.log(` siluzan-tso account withdraw-list`);
|
|
2070
|
+
for (const r of rows) {
|
|
2071
|
+
const cells = [
|
|
2072
|
+
media ? "" : r.mediaType.padEnd(cw.mediaType),
|
|
2073
|
+
r.mediaCustomerId.padEnd(cw.mediaCustomerId),
|
|
2074
|
+
r.advertiserName.padEnd(cw.advertiserName),
|
|
2075
|
+
r.mediaCustomerName.padEnd(cw.name),
|
|
2076
|
+
r.balance.padEnd(cw.balance),
|
|
2077
|
+
r.status
|
|
2078
|
+
].filter((_, i) => !media || i !== 0);
|
|
2079
|
+
console.log(" " + cells.join(" "));
|
|
1392
2080
|
}
|
|
1393
|
-
console.log();
|
|
1394
2081
|
}
|
|
1395
2082
|
|
|
1396
2083
|
// src/commands/balance.ts
|
|
@@ -1406,54 +2093,71 @@ async function runBalance(opts) {
|
|
|
1406
2093
|
);
|
|
1407
2094
|
process.exit(1);
|
|
1408
2095
|
}
|
|
2096
|
+
const media = opts.media;
|
|
2097
|
+
if (!BALANCE_SUPPORTED_MEDIA.includes(media)) {
|
|
2098
|
+
console.error(`
|
|
2099
|
+
\u26A0\uFE0F ${media} \u6682\u4E0D\u652F\u6301\u4F59\u989D\u67E5\u8BE2
|
|
2100
|
+
`);
|
|
2101
|
+
process.exit(1);
|
|
2102
|
+
}
|
|
1409
2103
|
const accountIds = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean);
|
|
1410
2104
|
if (accountIds.length === 0) {
|
|
1411
2105
|
console.error("\n\u274C \u8BF7\u901A\u8FC7 --accounts \u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u8D26\u6237 ID\uFF08\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF09\n");
|
|
1412
2106
|
process.exit(1);
|
|
1413
2107
|
}
|
|
1414
|
-
|
|
1415
|
-
params.set("ids", accountIds.join("|"));
|
|
1416
|
-
const url = `${config.apiBaseUrl}/query/media-account/${opts.media}/GetMediaAccountInfo?${params.toString()}`;
|
|
1417
|
-
let raw;
|
|
2108
|
+
let balanceMap;
|
|
1418
2109
|
try {
|
|
1419
|
-
|
|
2110
|
+
balanceMap = await fetchBalanceMap(media, accountIds, config, opts.startDate, opts.endDate, opts.verbose);
|
|
1420
2111
|
} catch (err) {
|
|
1421
2112
|
console.error(`
|
|
1422
2113
|
\u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
|
|
1423
2114
|
`);
|
|
1424
2115
|
process.exit(1);
|
|
1425
2116
|
}
|
|
1426
|
-
const items = Array.isArray(raw) ? raw : raw.items ?? [];
|
|
1427
2117
|
if (opts.json) {
|
|
1428
|
-
|
|
2118
|
+
const out = accountIds.map((id) => {
|
|
2119
|
+
const info = balanceMap.get(id);
|
|
2120
|
+
return {
|
|
2121
|
+
mediaCustomerId: id,
|
|
2122
|
+
remainingAccountBudget: info?.remainingAccountBudget ?? null,
|
|
2123
|
+
status: info?.status ?? null,
|
|
2124
|
+
currencyCode: info?.currencyCode ?? null,
|
|
2125
|
+
name: info?.name ?? null
|
|
2126
|
+
};
|
|
2127
|
+
});
|
|
2128
|
+
console.log(JSON.stringify(out, null, 2));
|
|
1429
2129
|
return;
|
|
1430
2130
|
}
|
|
1431
|
-
if (
|
|
1432
|
-
console.log("\n\u672A\u8FD4\u56DE\u4F59\u989D\u6570\u636E\uFF0C\u8BF7\u786E\u8BA4\u8D26\u6237 ID \u662F\u5426\u6B63\u786E\u3002\n");
|
|
2131
|
+
if (balanceMap.size === 0) {
|
|
2132
|
+
console.log("\n\u672A\u8FD4\u56DE\u4F59\u989D\u6570\u636E\uFF0C\u8BF7\u786E\u8BA4\u8D26\u6237 ID \u662F\u5426\u6B63\u786E\u4E14\u8D26\u6237\u72B6\u6001\u6709\u6548\u3002\n");
|
|
1433
2133
|
return;
|
|
1434
2134
|
}
|
|
1435
2135
|
console.log(`
|
|
1436
|
-
${
|
|
2136
|
+
${media} \u8D26\u6237\u4F59\u989D
|
|
1437
2137
|
`);
|
|
1438
2138
|
const colW = {
|
|
1439
|
-
id: Math.max(10, ...
|
|
1440
|
-
|
|
2139
|
+
id: Math.max(10, ...accountIds.map((id) => id.length)),
|
|
2140
|
+
name: Math.max(8, ...accountIds.map((id) => (balanceMap.get(id)?.name ?? "").length))
|
|
1441
2141
|
};
|
|
1442
2142
|
const header = [
|
|
1443
2143
|
"\u8D26\u6237ID".padEnd(colW.id),
|
|
1444
|
-
"\
|
|
2144
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(colW.name),
|
|
2145
|
+
"\u4F59\u989D".padEnd(12),
|
|
1445
2146
|
"\u5E01\u79CD".padEnd(6),
|
|
1446
|
-
"\
|
|
2147
|
+
"\u72B6\u6001"
|
|
1447
2148
|
].join(" ");
|
|
1448
2149
|
console.log(" " + header);
|
|
1449
2150
|
console.log(" " + "-".repeat(header.length));
|
|
1450
|
-
for (const
|
|
1451
|
-
const
|
|
2151
|
+
for (const id of accountIds) {
|
|
2152
|
+
const info = balanceMap.get(id);
|
|
2153
|
+
const balance = info?.remainingAccountBudget != null ? info.remainingAccountBudget.toFixed(2).padEnd(12) : "N/A".padEnd(12);
|
|
2154
|
+
const status = info?.status ?? info?.accountStatus ?? "N/A";
|
|
1452
2155
|
const row = [
|
|
1453
|
-
|
|
2156
|
+
id.padEnd(colW.id),
|
|
2157
|
+
(info?.name ?? "").padEnd(colW.name),
|
|
1454
2158
|
balance,
|
|
1455
|
-
(
|
|
1456
|
-
|
|
2159
|
+
(info?.currencyCode ?? info?.currency ?? "").padEnd(6),
|
|
2160
|
+
status
|
|
1457
2161
|
].join(" ");
|
|
1458
2162
|
console.log(" " + row);
|
|
1459
2163
|
}
|
|
@@ -1462,13 +2166,13 @@ ${opts.media} \u8D26\u6237\u5B9E\u65F6\u4F59\u989D
|
|
|
1462
2166
|
|
|
1463
2167
|
// src/commands/stats.ts
|
|
1464
2168
|
var VALID_MEDIA_TYPES3 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
|
|
1465
|
-
function
|
|
2169
|
+
function defaultDateRange2() {
|
|
1466
2170
|
const end = /* @__PURE__ */ new Date();
|
|
1467
2171
|
end.setDate(end.getDate() - 1);
|
|
1468
2172
|
const start = new Date(end);
|
|
1469
2173
|
start.setDate(start.getDate() - 6);
|
|
1470
|
-
const
|
|
1471
|
-
return { startDate:
|
|
2174
|
+
const fmt2 = (d) => d.toISOString().slice(0, 10);
|
|
2175
|
+
return { startDate: fmt2(start), endDate: fmt2(end) };
|
|
1472
2176
|
}
|
|
1473
2177
|
async function runStats(opts) {
|
|
1474
2178
|
const config = loadConfig(opts.token);
|
|
@@ -1482,7 +2186,7 @@ async function runStats(opts) {
|
|
|
1482
2186
|
process.exit(1);
|
|
1483
2187
|
}
|
|
1484
2188
|
const { startDate, endDate } = {
|
|
1485
|
-
...
|
|
2189
|
+
...defaultDateRange2(),
|
|
1486
2190
|
...opts.startDate ? { startDate: opts.startDate } : {},
|
|
1487
2191
|
...opts.endDate ? { endDate: opts.endDate } : {}
|
|
1488
2192
|
};
|
|
@@ -2269,27 +2973,55 @@ ${label}\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 $
|
|
|
2269
2973
|
console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
|
|
2270
2974
|
return;
|
|
2271
2975
|
}
|
|
2976
|
+
const rows = items.map((item, idx) => ({
|
|
2977
|
+
idx: idx + 1 + (page - 1) * pageSize,
|
|
2978
|
+
tradeNo: String(item.tradeNo ?? item["orderNo"] ?? item["rechargeNo"] ?? "-").trim() || "-",
|
|
2979
|
+
entityId: String(item.entityId ?? "").trim() || "-",
|
|
2980
|
+
media: item.mediaAccountType ?? "",
|
|
2981
|
+
currency: item.currencyCode ?? "",
|
|
2982
|
+
amount: String(item.amounts ?? ""),
|
|
2983
|
+
state: item.invoiceState ?? item.rechargeStatus ?? "",
|
|
2984
|
+
name: item.mediaCustomerName ?? "",
|
|
2985
|
+
time: (item.createdDateTime ?? "").slice(0, 19)
|
|
2986
|
+
}));
|
|
2987
|
+
const cw = {
|
|
2988
|
+
no: Math.max(4, String(Math.max(...rows.map((r) => r.idx))).length),
|
|
2989
|
+
order: Math.max(10, ...rows.map((r) => r.tradeNo.length)),
|
|
2990
|
+
eid: Math.max(12, ...rows.map((r) => r.entityId.length)),
|
|
2991
|
+
media: Math.max(8, ...rows.map((r) => r.media.length)),
|
|
2992
|
+
cur: Math.max(6, ...rows.map((r) => r.currency.length)),
|
|
2993
|
+
amt: Math.max(8, ...rows.map((r) => r.amount.length)),
|
|
2994
|
+
st: Math.max(8, ...rows.map((r) => r.state.length)),
|
|
2995
|
+
name: Math.max(10, ...rows.map((r) => r.name.length))
|
|
2996
|
+
};
|
|
2997
|
+
const sep = " ";
|
|
2272
2998
|
const header = [
|
|
2273
|
-
"
|
|
2274
|
-
"\
|
|
2275
|
-
"\
|
|
2276
|
-
"\
|
|
2277
|
-
"\
|
|
2999
|
+
"#".padStart(cw.no),
|
|
3000
|
+
"\u8BA2\u5355\u53F7".padEnd(cw.order),
|
|
3001
|
+
"entityId(\u5F00\u7968\u7528)".padEnd(cw.eid),
|
|
3002
|
+
"\u5A92\u4F53".padEnd(cw.media),
|
|
3003
|
+
"\u5E01\u79CD".padEnd(cw.cur),
|
|
3004
|
+
"\u91D1\u989D".padEnd(cw.amt),
|
|
3005
|
+
"\u72B6\u6001".padEnd(cw.st),
|
|
3006
|
+
"\u8D26\u6237\u540D\u79F0".padEnd(cw.name),
|
|
2278
3007
|
"\u521B\u5EFA\u65F6\u95F4"
|
|
2279
|
-
].join(
|
|
3008
|
+
].join(sep);
|
|
2280
3009
|
console.log(" " + header);
|
|
2281
3010
|
console.log(" " + "-".repeat(header.length));
|
|
2282
|
-
for (const
|
|
3011
|
+
for (const r of rows) {
|
|
2283
3012
|
console.log(" " + [
|
|
2284
|
-
(
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
(
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
3013
|
+
String(r.idx).padStart(cw.no),
|
|
3014
|
+
r.tradeNo.padEnd(cw.order),
|
|
3015
|
+
r.entityId.padEnd(cw.eid),
|
|
3016
|
+
r.media.padEnd(cw.media),
|
|
3017
|
+
r.currency.padEnd(cw.cur),
|
|
3018
|
+
r.amount.padEnd(cw.amt),
|
|
3019
|
+
r.state.padEnd(cw.st),
|
|
3020
|
+
r.name.padEnd(cw.name),
|
|
3021
|
+
r.time
|
|
3022
|
+
].join(sep));
|
|
3023
|
+
}
|
|
3024
|
+
console.log('\n \u5F00\u7968\u65F6\u8BF7\u628A\u6240\u9009\u884C\u7684 entityId \u4F20\u7ED9\uFF1Asiluzan-tso invoice apply --bill-ids "<entityId>" ...\n');
|
|
2293
3025
|
}
|
|
2294
3026
|
async function runInvoiceApply(opts) {
|
|
2295
3027
|
const config = await ensureDataPermission(loadConfig(opts.token));
|
|
@@ -7760,11 +8492,13 @@ program.command("balance").description("\u67E5\u8BE2\u5E7F\u544A\u8D26\u6237\u5B
|
|
|
7760
8492
|
).requiredOption(
|
|
7761
8493
|
"-a, --accounts <ids>",
|
|
7762
8494
|
"\u8D26\u6237 ID\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u6765\u81EA list-accounts \u7684 mediaCustomerId\uFF09"
|
|
7763
|
-
).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
8495
|
+
).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--start-date <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F yyyy-MM-dd\uFF08\u9ED8\u8BA4\uFF1A7 \u5929\u524D\uFF0CMetaAd \u4E0D\u9700\u8981\uFF09").option("--end-date <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F yyyy-MM-dd\uFF08\u9ED8\u8BA4\uFF1A\u4ECA\u5929\uFF0CMetaAd \u4E0D\u9700\u8981\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
|
|
7764
8496
|
await runBalance({
|
|
7765
8497
|
token: opts.token,
|
|
7766
8498
|
media: opts.media,
|
|
7767
8499
|
accounts: opts.accounts,
|
|
8500
|
+
startDate: opts.startDate,
|
|
8501
|
+
endDate: opts.endDate,
|
|
7768
8502
|
json: opts.json,
|
|
7769
8503
|
verbose: opts.verbose
|
|
7770
8504
|
});
|
package/dist/skill/_meta.json
CHANGED
|
@@ -340,3 +340,35 @@ siluzan-tso invoice apply \
|
|
|
340
340
|
--recipient-phone 13800138000 \
|
|
341
341
|
--recipient-email zhang@example.com
|
|
342
342
|
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
### AI 助手:订单开票对话智能点
|
|
347
|
+
|
|
348
|
+
当用户表达「给订单开发票」「申请开票」「充值要开票」等意图时,助手应**分步引导**,顺序如下。
|
|
349
|
+
|
|
350
|
+
#### 1. 先让用户选择订单
|
|
351
|
+
|
|
352
|
+
- 执行 `siluzan-tso invoice billable`(按需加 `-m`、`-c`、`--wallet`、日期范围等),把结果整理成**可读的订单列表**(建议标注:金额、币种、时间、媒体、`entityId`)。
|
|
353
|
+
- **必须**请用户明确要开哪一笔或哪几笔(可多选),得到确认的 `bill-ids`(`entityId` 逗号分隔)和 `bill-type`(`AmountAccount` / `WalletRecharge`)之后,再进入抬头环节。
|
|
354
|
+
- 不要替用户猜测订单;未确认订单前不要直接 `invoice apply`。
|
|
355
|
+
|
|
356
|
+
#### 2. 再让用户选择发票抬头
|
|
357
|
+
|
|
358
|
+
- 根据已选订单的**币种**确定允许的发票类型(与上文规则一致:人民币 → `VATI`/`VATSI`;外币 → `PI`)。
|
|
359
|
+
- 执行 `siluzan-tso invoice-info list --invoice-type <PI|VATI|VATSI>`(需要结构化数据时用 `--json`),向用户展示**已保存的发票抬头列表**。
|
|
360
|
+
- 请用户**从列表中选一条**(按 id 或公司名/抬头说明),或明确说要用**新的自定义抬头**。
|
|
361
|
+
|
|
362
|
+
#### 3. 自定义抬头:先匹配列表,没有再创建
|
|
363
|
+
|
|
364
|
+
- 用户给出自定义抬头(公司名、税号、抬头文案、地址、联系人等)时:
|
|
365
|
+
1. 先用 `invoice-info list`(可加 `-k` 关键字、`--invoice-type`)在**已有抬头**中检索:公司名、`title`、税号等与用户输入是否**实质相同**(允许轻微空格/标点差异)。
|
|
366
|
+
2. **若已存在等价记录**:不要重复 `invoice-info create`;直接沿用该条里的字段填 `invoice apply`(与 Web 一致:`apply` 传的是完整 `InvoiceInfomation`,不是只传抬头 id)。
|
|
367
|
+
3. **若不存在**:先 `siluzan-tso invoice-info create ...` 创建成功,再 `siluzan-tso invoice apply ...`。避免未落库就假定「已保存」。
|
|
368
|
+
|
|
369
|
+
#### 4. 最后调用开票接口
|
|
370
|
+
|
|
371
|
+
- 组装 `invoice apply`:`--bill-ids`、`--bill-type`、`--invoice-type`、收件人信息,以及 PI 与 VATI/VATSI 各自必填的抬头字段(见上表)。
|
|
372
|
+
- 默认保留 CLI 的币种与发票类型校验;仅在用户理解风险时使用 `--skip-currency-check`。
|
|
373
|
+
|
|
374
|
+
**避免**:跳过订单选择;不展示 `invoice billable` 就让用户手写 id;对自定义抬头不做查重、反复 `create` 造成多条重复抬头。
|