koishi-plugin-prism 0.1.4 → 0.1.6
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 +48 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
| `provider` | `string` | `"qq"` | 当前绑定的账号提供商平台名称(如 `"qq"`,`"discord"`)。 |
|
|
25
25
|
| `autoRegister` | `boolean` | `true` | 当玩家未注册时,是否在首次操作(如入场/查钱包)时自动在 PRiSM 中创建新玩家。 |
|
|
26
26
|
| `loginPricingConfigIds` | `string[]` | `[]` | 默认入场计费规则 ID 列表。 |
|
|
27
|
-
| `loginSessionLabel` | `string` |
|
|
27
|
+
| `loginSessionLabel` | `string` | `"音游区间"` | 默认入场会话的标签文本。后端会按该标签对同一玩家的活跃会话去重,重复入场会被拒绝并提示。留空则不启用去重。 |
|
|
28
28
|
| `defaultDoorDeviceId` | `string` | - | 默认门锁设备的 ID,用于开门指令。 |
|
|
29
29
|
| `defaultScanProvider` | `string` | `"aime"` | 默认模拟刷卡时的读卡器协议提供商(如 `"aime"`)。 |
|
|
30
30
|
| `currencyName` | `string` | `"金币"` | 账户货币在显示时的自定义单位名称。 |
|
package/lib/index.js
CHANGED
|
@@ -16,7 +16,10 @@ exports.Config = koishi_1.Schema.object({
|
|
|
16
16
|
currencyName: koishi_1.Schema.string().default("猫粮").description("代币名称"),
|
|
17
17
|
defaultDoorDeviceId: koishi_1.Schema.string().default("front-door").description("默认开门设备ID"),
|
|
18
18
|
defaultScanProvider: koishi_1.Schema.string().default("aime").description("默认刷卡提供商"),
|
|
19
|
+
loginPricingConfigIds: koishi_1.Schema.array(koishi_1.Schema.string()).default([]).description("默认入场绑定的计费策略ID"),
|
|
20
|
+
loginSessionLabel: koishi_1.Schema.string().default("音游区间").description("默认入场场次标签 (防重复入场)"),
|
|
19
21
|
enableStaffCommands: koishi_1.Schema.boolean().default(false).description("是否启用管理员指令"),
|
|
22
|
+
staffUserIds: koishi_1.Schema.array(koishi_1.Schema.string()).default([]).description("允许执行管理员指令的平台用户ID列表"),
|
|
20
23
|
powerOffInterval: koishi_1.Schema.number().default(0).description("无人自动关机等待秒数 (0为禁用)"),
|
|
21
24
|
mahjongTables: koishi_1.Schema.string().description("麻将桌配置"),
|
|
22
25
|
mahjongTableSize: koishi_1.Schema.number().default(4).description("麻将桌人数限制"),
|
|
@@ -709,6 +712,15 @@ class PrismKoishiService {
|
|
|
709
712
|
return null;
|
|
710
713
|
}
|
|
711
714
|
}
|
|
715
|
+
async resolvePlayerDisplay(sender, playerId) {
|
|
716
|
+
if (!sender)
|
|
717
|
+
return playerId || "未知玩家";
|
|
718
|
+
const platformName = await this.resolvePlatformName(sender.id);
|
|
719
|
+
const name = platformName
|
|
720
|
+
|| (sender.name && sender.name !== sender.id ? sender.name : playerId)
|
|
721
|
+
|| sender.id;
|
|
722
|
+
return `玩家:${name}(${this.config.provider.toUpperCase()}:${sender.id})`;
|
|
723
|
+
}
|
|
712
724
|
mahjongTableForPlayer(playerId) {
|
|
713
725
|
for (const [tableId, state] of this.mahjongTables) {
|
|
714
726
|
if (state.activeSessions[playerId])
|
|
@@ -752,7 +764,7 @@ class PrismKoishiService {
|
|
|
752
764
|
return "权限不足";
|
|
753
765
|
return null;
|
|
754
766
|
}
|
|
755
|
-
formatCheckoutPreview(result, sender, title = "【结算账单】") {
|
|
767
|
+
async formatCheckoutPreview(result, sender, title = "【结算账单】") {
|
|
756
768
|
if (result?.billing && result?.session) {
|
|
757
769
|
return formatLegacyBilling(result, this.config.currencyName);
|
|
758
770
|
}
|
|
@@ -782,57 +794,57 @@ class PrismKoishiService {
|
|
|
782
794
|
const adjustments = result?.adjustments ?? [];
|
|
783
795
|
const assetHoldings = result?.assetHoldings ?? [];
|
|
784
796
|
const lines = [];
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const identitySuffix = sender ? `(${this.config.provider.toUpperCase()}:${sender.id})` : "";
|
|
788
|
-
headerParts.push(`玩家ID:${playerId}${identitySuffix}`);
|
|
789
|
-
}
|
|
790
|
-
else if (sender) {
|
|
791
|
-
headerParts.push(`玩家:${sender.name || sender.id}(${this.config.provider.toUpperCase()}:${sender.id})`);
|
|
792
|
-
}
|
|
793
|
-
lines.push(headerParts.join("\n"));
|
|
797
|
+
lines.push(title);
|
|
798
|
+
lines.push(await this.resolvePlayerDisplay(sender, playerId));
|
|
794
799
|
const validStarts = sessionPreviews.map((s) => parseDateTime(s?.startedAt)).filter(Boolean);
|
|
795
800
|
const validEnds = sessionPreviews.map((s) => sessionDisplayEnd(s, previewedAt)).filter(Boolean);
|
|
796
801
|
if (validStarts.length > 0) {
|
|
797
802
|
const overallStart = minDate(validStarts);
|
|
798
803
|
const overallEnd = validEnds.length > 0 ? maxDate(validEnds) : now(this.config);
|
|
799
|
-
lines.push(
|
|
804
|
+
lines.push(`⏰ 游玩时间:${formatHM(overallStart)}–${formatHM(overallEnd)}`);
|
|
800
805
|
}
|
|
801
|
-
lines.push("");
|
|
802
806
|
for (const sPrev of sessionPreviews) {
|
|
803
807
|
const label = sPrev?.label || "计时区间";
|
|
804
808
|
const startDt = parseDateTime(sPrev?.startedAt);
|
|
805
809
|
const endDt = sessionDisplayEnd(sPrev, previewedAt);
|
|
806
810
|
const status = sPrev?.status ?? "active";
|
|
807
811
|
const sTotal = toNumber(sPrev?.total ?? 0);
|
|
812
|
+
lines.push("");
|
|
808
813
|
lines.push(label);
|
|
809
814
|
if (startDt && endDt) {
|
|
815
|
+
const minutes = Math.floor((endDt.getTime() - startDt.getTime()) / 60_000);
|
|
810
816
|
lines.push(`游玩时段:${formatHM(startDt)}-${formatHM(endDt)}`);
|
|
811
|
-
lines.push(`游玩时长:${formatDurationValue(
|
|
817
|
+
lines.push(`游玩时长:${formatDurationValue(minutes)}|消费:${formatNumber(sTotal)}${currency}`);
|
|
812
818
|
}
|
|
813
819
|
else if (startDt) {
|
|
814
820
|
lines.push(`入场:${formatHM(startDt)} (${status === "active" ? "计费中" : "已关闭"})`);
|
|
815
821
|
}
|
|
816
|
-
|
|
822
|
+
const sessionAdjustments = (sPrev?.adjustments ?? []);
|
|
823
|
+
for (const adj of sessionAdjustments) {
|
|
824
|
+
const amount = toNumber(firstDefined(adj ?? {}, "amount", "saved", 0));
|
|
825
|
+
if (amount === 0)
|
|
826
|
+
continue;
|
|
827
|
+
const adjLabel = firstDefined(adj ?? {}, "label", "name", "source") ?? "优惠";
|
|
828
|
+
lines.push(` └ ${adjLabel}:${formatNumber(amount)}${currency}`);
|
|
829
|
+
}
|
|
817
830
|
}
|
|
818
|
-
|
|
819
|
-
|
|
831
|
+
let balance = 0;
|
|
832
|
+
let hasBalance = false;
|
|
820
833
|
for (const holding of assetHoldings) {
|
|
821
|
-
const qty = toNumber(holding?.quantity ?? 0);
|
|
822
834
|
const code = String(holding?.assetCode ?? "").toLowerCase();
|
|
823
835
|
if (code.includes("paid") || code.includes("free") || code.includes("currency")) {
|
|
824
|
-
|
|
836
|
+
balance += toNumber(holding?.quantity ?? 0);
|
|
837
|
+
hasBalance = true;
|
|
825
838
|
}
|
|
826
839
|
}
|
|
827
|
-
|
|
828
|
-
lines.push(`扣款后余额:${balanceParts.join("+")}`);
|
|
840
|
+
lines.push("");
|
|
829
841
|
lines.push(`计费总价:${formatNumber(subtotal)}${currency}`);
|
|
830
|
-
const hasDiscount = adjustments.some((adj) => {
|
|
831
|
-
|
|
832
|
-
return amount !== 0;
|
|
833
|
-
});
|
|
842
|
+
const hasDiscount = adjustments.some((adj) => toNumber(firstDefined(adj ?? {}, "amount", "saved", 0)) !== 0)
|
|
843
|
+
|| sessionPreviews.some((sp) => (sp?.adjustments ?? []).some((adj) => toNumber(firstDefined(adj ?? {}, "amount", "saved", 0)) !== 0));
|
|
834
844
|
if (hasDiscount)
|
|
835
845
|
lines.push(`优惠后价格:${formatNumber(total)}${currency}`);
|
|
846
|
+
if (hasBalance)
|
|
847
|
+
lines.push(`扣款后余额:${formatNumber(balance)}${currency}`);
|
|
836
848
|
return lines.join("\n");
|
|
837
849
|
}
|
|
838
850
|
handleCommandError(error) {
|
|
@@ -846,6 +858,18 @@ class PrismKoishiService {
|
|
|
846
858
|
}
|
|
847
859
|
}
|
|
848
860
|
function humanReadableBotError(error) {
|
|
861
|
+
if (error.code === "DUPLICATE_SESSION_LABEL") {
|
|
862
|
+
return "❌ 您已经处于入场状态,请勿重复发送入场命令。";
|
|
863
|
+
}
|
|
864
|
+
if (error.code === "PLAYER_HAS_NO_UNSETTLED_SESSIONS") {
|
|
865
|
+
return "您当前没有未结算的账单,无需结账。";
|
|
866
|
+
}
|
|
867
|
+
if (error.code === "ACTIVE_SESSION_NOT_FOUND") {
|
|
868
|
+
return "您当前没有进行中的计费场次。";
|
|
869
|
+
}
|
|
870
|
+
if (error.code === "PLAYER_IDENTITY_NOT_FOUND") {
|
|
871
|
+
return "未找到您的玩家身份,请先注册或绑定账号。";
|
|
872
|
+
}
|
|
849
873
|
if (error.code === "INSUFFICIENT_BALANCE") {
|
|
850
874
|
return "余额不足,暂时不能结账。请先充值,或由店员在后台改价后再结账。";
|
|
851
875
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-prism",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
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
|
+
}
|