koishi-plugin-prism 0.1.28 → 0.1.30
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/lib/index.js +27 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ pricingConfigIds: [pricing-mahjong-a]
|
|
|
58
58
|
玩家在未产生任何费用时退场,机器人会简洁显示“本次未产生费用”和当前余额;存在收费或优惠明细时仍显示完整结算账单。
|
|
59
59
|
结账成功回执中的余额为后端已经完成扣款后的余额;只有 `/billing` 预览会显示当前余额与预计结账后余额。
|
|
60
60
|
方案内区间封顶直接计入对应计时费用;全局封顶按日期和时段逐条列出,不合并、不截断,并直接形成计费总价,不作为优惠。若旧后端未返回结构化封顶窗口,插件会用封顶历史恢复原价与计入金额,不会显示内部 adjustment 差额。只作用于整次结账的资产优惠直接列在计费总价下方,不显示额外标题或 emoji,也不会误归属到最后一个 session。
|
|
61
|
-
|
|
61
|
+
在玩家退场或管理员覆盖结账成功后,机器人会向 `staffUserIds` 与 `logoutNotifyUserIds` 中的用户私聊同一份账单,账单会明确显示结账玩家身份。
|
|
62
62
|
同一玩家在前一次退场结账尚未完成时重复发送 `/logout` 或 `/退场`,机器人会复用同一次结账请求与账单,避免重复扣款。
|
|
63
63
|
账单和管理员代操作回执均使用“平台昵称(QQ:号码)”称呼玩家;平台暂时无法提供昵称时显示“未知昵称(QQ:号码)”,不会显示内部玩家 ID。
|
|
64
64
|
管理员 `/add` 增加免费余额;`/del` 按结账相同的顺序从可用免费余额、再从付费余额扣除,余额不足时会返回余额不足提示。
|
package/lib/index.js
CHANGED
|
@@ -389,8 +389,11 @@ class PrismKoishiService {
|
|
|
389
389
|
if (!Number.isFinite(total) || total < 0)
|
|
390
390
|
return "金额必须为非负数";
|
|
391
391
|
const reason = cleanText(rawReason) || "Koishi 管理员手动调价";
|
|
392
|
-
await this.client.checkoutWithOverrideByIdentity(this.identity(sender), total, reason);
|
|
393
|
-
|
|
392
|
+
const result = (await this.client.checkoutWithOverrideByIdentity(this.identity(sender), total, reason));
|
|
393
|
+
const playerId = String(result?.playerSettlement?.playerId ?? result?.settlement?.playerId ?? "");
|
|
394
|
+
if (playerId)
|
|
395
|
+
this.removeMahjongPlayer(playerId);
|
|
396
|
+
return this.formatAndNotifyCheckout(result, sender, "✅ 覆盖结账成功 · 结算账单", bot);
|
|
394
397
|
}, bot);
|
|
395
398
|
}
|
|
396
399
|
async mahjongJoin(sender, rawTableId) {
|
|
@@ -524,6 +527,12 @@ class PrismKoishiService {
|
|
|
524
527
|
}
|
|
525
528
|
async performLogout(sender, bot) {
|
|
526
529
|
const result = (await this.client.confirmCheckoutByIdentity(this.identity(sender), false));
|
|
530
|
+
const playerId = String(result?.playerSettlement?.playerId ?? result?.settlement?.playerId ?? "");
|
|
531
|
+
if (playerId)
|
|
532
|
+
this.removeMahjongPlayer(playerId);
|
|
533
|
+
return this.formatAndNotifyCheckout(result, sender, "✅ 退场成功 · 结算账单", bot);
|
|
534
|
+
}
|
|
535
|
+
async formatAndNotifyCheckout(result, sender, title, bot) {
|
|
527
536
|
const settlement = result?.playerSettlement ?? result?.settlement ?? {};
|
|
528
537
|
const records = result?.settlements ?? [];
|
|
529
538
|
const checkoutAdjustments = (result?.checkoutAdjustments ?? []);
|
|
@@ -565,10 +574,11 @@ class PrismKoishiService {
|
|
|
565
574
|
globalCapWindows: result?.globalCapWindows ?? [],
|
|
566
575
|
assetHoldings: result?.assetHoldings ?? [],
|
|
567
576
|
};
|
|
568
|
-
const receipt = await this.formatCheckoutPreview(synthetic, sender,
|
|
577
|
+
const receipt = await this.formatCheckoutPreview(synthetic, sender, title);
|
|
569
578
|
const recipients = [...new Set([...(this.config.staffUserIds ?? []), ...(this.config.logoutNotifyUserIds ?? [])])];
|
|
570
579
|
if (recipients.length > 0 && bot?.broadcast) {
|
|
571
|
-
|
|
580
|
+
const channelIds = recipients.map((id) => (id.includes(":") ? id : `private:${id}`));
|
|
581
|
+
await bot.broadcast(channelIds, receipt);
|
|
572
582
|
}
|
|
573
583
|
return receipt;
|
|
574
584
|
}
|
|
@@ -808,6 +818,12 @@ class PrismKoishiService {
|
|
|
808
818
|
}
|
|
809
819
|
return null;
|
|
810
820
|
}
|
|
821
|
+
removeMahjongPlayer(playerId) {
|
|
822
|
+
for (const state of this.mahjongTables.values()) {
|
|
823
|
+
delete state.activeSessions[playerId];
|
|
824
|
+
state.waiting = state.waiting.filter((seat) => seat.playerId !== playerId);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
811
827
|
mahjongTableConfigs() {
|
|
812
828
|
return resolveMahjongTableConfigs(this.config.mahjongTableConfigs ?? [], this.config.mahjongTables ?? "", this.config.mahjongLabelPrefix ?? "麻将桌");
|
|
813
829
|
}
|
|
@@ -817,6 +833,9 @@ class PrismKoishiService {
|
|
|
817
833
|
mahjongSessionLabel(table, this.config.mahjongLabelPrefix ?? "麻将桌"),
|
|
818
834
|
table,
|
|
819
835
|
]));
|
|
836
|
+
// All playerIds that still have at least one active session in the backend.
|
|
837
|
+
// Used to evict waiting seats for players who have fully checked out externally.
|
|
838
|
+
const allActivePlayerIds = new Set(sessions.map((s) => String(s.playerId ?? "")).filter(Boolean));
|
|
820
839
|
const activeByTable = new Map();
|
|
821
840
|
for (const session of sessions) {
|
|
822
841
|
const table = tableByLabel.get(session.label ?? "");
|
|
@@ -831,7 +850,9 @@ class PrismKoishiService {
|
|
|
831
850
|
for (const table of tables) {
|
|
832
851
|
const state = this.mahjongTables.get(table.tableId) ?? { waiting: [], activeSessions: {} };
|
|
833
852
|
state.activeSessions = activeByTable.get(table.tableId) ?? {};
|
|
834
|
-
|
|
853
|
+
// Remove seats that have been promoted to active, or whose players have
|
|
854
|
+
// fully left the backend (no entry session remaining — orphan eviction).
|
|
855
|
+
state.waiting = state.waiting.filter((seat) => !state.activeSessions[seat.playerId] && allActivePlayerIds.has(seat.playerId));
|
|
835
856
|
if (state.waiting.length > 0 || Object.keys(state.activeSessions).length > 0 || this.mahjongTables.has(table.tableId)) {
|
|
836
857
|
this.mahjongTables.set(table.tableId, state);
|
|
837
858
|
}
|
|
@@ -966,7 +987,7 @@ class PrismKoishiService {
|
|
|
966
987
|
if (startDt && endDt) {
|
|
967
988
|
const minutes = Math.floor((endDt.getTime() - startDt.getTime()) / 60_000);
|
|
968
989
|
lines.push(`游玩时段:${formatHM(startDt)}-${formatHM(endDt)}`);
|
|
969
|
-
lines.push(`游玩时长:${formatDurationValue(minutes)}
|
|
990
|
+
lines.push(`游玩时长:${formatDurationValue(minutes)}|计价:${formatNumber(sTotal)}${currency}`);
|
|
970
991
|
}
|
|
971
992
|
else if (startDt) {
|
|
972
993
|
lines.push(`入场:${formatHM(startDt)} (${status === "active" ? "计费中" : "已关闭"})`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-prism",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "PRiSM Next 计费与设备管理系统的 Koishi 机器人集成插件",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -48,4 +48,4 @@
|
|
|
48
48
|
"test": "bun test test",
|
|
49
49
|
"typecheck": "tsc -p tsconfig.json"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
}
|