napgram-plugin-slave-market 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.
- package/README.md +248 -0
- package/dist/commands/admin.commands.d.ts +11 -0
- package/dist/commands/admin.commands.d.ts.map +1 -0
- package/dist/commands/admin.commands.js +268 -0
- package/dist/commands/bank.commands.d.ts +13 -0
- package/dist/commands/bank.commands.d.ts.map +1 -0
- package/dist/commands/bank.commands.js +211 -0
- package/dist/commands/base.commands.d.ts +12 -0
- package/dist/commands/base.commands.d.ts.map +1 -0
- package/dist/commands/base.commands.js +149 -0
- package/dist/commands/economy.commands.d.ts +13 -0
- package/dist/commands/economy.commands.d.ts.map +1 -0
- package/dist/commands/economy.commands.js +221 -0
- package/dist/commands/gameplay.commands.d.ts +15 -0
- package/dist/commands/gameplay.commands.d.ts.map +1 -0
- package/dist/commands/gameplay.commands.js +461 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +47 -0
- package/dist/commands/social.commands.d.ts +13 -0
- package/dist/commands/social.commands.d.ts.map +1 -0
- package/dist/commands/social.commands.js +305 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.mjs +57 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +40 -0
- package/dist/services/admin.service.d.ts +59 -0
- package/dist/services/admin.service.d.ts.map +1 -0
- package/dist/services/admin.service.js +164 -0
- package/dist/services/bank.service.d.ts +74 -0
- package/dist/services/bank.service.d.ts.map +1 -0
- package/dist/services/bank.service.js +354 -0
- package/dist/services/bodyguard.service.d.ts +36 -0
- package/dist/services/bodyguard.service.d.ts.map +1 -0
- package/dist/services/bodyguard.service.js +102 -0
- package/dist/services/cooldown.service.d.ts +33 -0
- package/dist/services/cooldown.service.d.ts.map +1 -0
- package/dist/services/cooldown.service.js +104 -0
- package/dist/services/farm.service.d.ts +61 -0
- package/dist/services/farm.service.d.ts.map +1 -0
- package/dist/services/farm.service.js +255 -0
- package/dist/services/index.d.ts +16 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +15 -0
- package/dist/services/market.service.d.ts +58 -0
- package/dist/services/market.service.d.ts.map +1 -0
- package/dist/services/market.service.js +286 -0
- package/dist/services/player.service.d.ts +56 -0
- package/dist/services/player.service.d.ts.map +1 -0
- package/dist/services/player.service.js +201 -0
- package/dist/services/ranking.service.d.ts +28 -0
- package/dist/services/ranking.service.d.ts.map +1 -0
- package/dist/services/ranking.service.js +71 -0
- package/dist/services/redpacket.service.d.ts +63 -0
- package/dist/services/redpacket.service.d.ts.map +1 -0
- package/dist/services/redpacket.service.js +207 -0
- package/dist/services/transaction.service.d.ts +48 -0
- package/dist/services/transaction.service.d.ts.map +1 -0
- package/dist/services/transaction.service.js +102 -0
- package/dist/services/vip.service.d.ts +41 -0
- package/dist/services/vip.service.d.ts.map +1 -0
- package/dist/services/vip.service.js +167 -0
- package/dist/services/work.service.d.ts +49 -0
- package/dist/services/work.service.d.ts.map +1 -0
- package/dist/services/work.service.js +258 -0
- package/dist/types/index.d.ts +62 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/helpers.d.ts +40 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +88 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/napgram-plugin.json +15 -0
- package/package.json +56 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 管理员服务 - 系统管理、数据维护
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from '../models';
|
|
5
|
+
export class AdminService {
|
|
6
|
+
ctx;
|
|
7
|
+
config;
|
|
8
|
+
constructor(ctx, config) {
|
|
9
|
+
this.ctx = ctx;
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 添加管理员
|
|
14
|
+
*/
|
|
15
|
+
async addAdmin(adminId, targetId, targetName) {
|
|
16
|
+
const db = getDatabase();
|
|
17
|
+
// 检查是否已是管理员
|
|
18
|
+
const existing = await db.slaveMarketAdmin.findUnique({
|
|
19
|
+
where: { userId: targetId },
|
|
20
|
+
});
|
|
21
|
+
if (existing) {
|
|
22
|
+
throw new Error('该用户已经是管理员');
|
|
23
|
+
}
|
|
24
|
+
await db.slaveMarketAdmin.create({
|
|
25
|
+
data: {
|
|
26
|
+
userId: targetId,
|
|
27
|
+
nickname: targetName,
|
|
28
|
+
addedBy: adminId,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
// 同时更新玩家记录
|
|
32
|
+
const player = await db.slaveMarketPlayer.findUnique({
|
|
33
|
+
where: { userId: targetId },
|
|
34
|
+
});
|
|
35
|
+
if (player) {
|
|
36
|
+
await db.slaveMarketPlayer.update({
|
|
37
|
+
where: { userId: targetId },
|
|
38
|
+
data: { isAdmin: true },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 移除管理员
|
|
44
|
+
*/
|
|
45
|
+
async removeAdmin(targetId) {
|
|
46
|
+
const db = getDatabase();
|
|
47
|
+
await db.slaveMarketAdmin.delete({
|
|
48
|
+
where: { userId: targetId },
|
|
49
|
+
});
|
|
50
|
+
// 同时更新玩家记录
|
|
51
|
+
const player = await db.slaveMarketPlayer.findUnique({
|
|
52
|
+
where: { userId: targetId },
|
|
53
|
+
});
|
|
54
|
+
if (player) {
|
|
55
|
+
await db.slaveMarketPlayer.update({
|
|
56
|
+
where: { userId: targetId },
|
|
57
|
+
data: { isAdmin: false },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 重置游戏数据
|
|
63
|
+
*/
|
|
64
|
+
async resetGame() {
|
|
65
|
+
const db = getDatabase();
|
|
66
|
+
const [transactions, farmLands, appearances, redPacketGrabs, redPackets, vipCards, admins, systemConfigs, players,] = await Promise.all([
|
|
67
|
+
db.slaveMarketTransaction.deleteMany(),
|
|
68
|
+
db.slaveMarketFarmLand.deleteMany(),
|
|
69
|
+
db.slaveMarketAppearance.deleteMany(),
|
|
70
|
+
db.slaveMarketRedPacketGrab.deleteMany(),
|
|
71
|
+
db.slaveMarketRedPacket.deleteMany(),
|
|
72
|
+
db.slaveMarketVipCard.deleteMany(),
|
|
73
|
+
db.slaveMarketAdmin.deleteMany(),
|
|
74
|
+
db.slaveMarketSystem.deleteMany(),
|
|
75
|
+
db.slaveMarketPlayer.deleteMany(),
|
|
76
|
+
]);
|
|
77
|
+
this.ctx.logger.info('[slave-market] Game data reset completed');
|
|
78
|
+
return {
|
|
79
|
+
players: players.count,
|
|
80
|
+
transactions: transactions.count,
|
|
81
|
+
farmLands: farmLands.count,
|
|
82
|
+
redPackets: redPackets.count,
|
|
83
|
+
redPacketGrabs: redPacketGrabs.count,
|
|
84
|
+
appearances: appearances.count,
|
|
85
|
+
vipCards: vipCards.count,
|
|
86
|
+
admins: admins.count,
|
|
87
|
+
systemConfigs: systemConfigs.count,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 获取系统统计
|
|
92
|
+
*/
|
|
93
|
+
async getSystemStats() {
|
|
94
|
+
const db = getDatabase();
|
|
95
|
+
const [players, transactions] = await Promise.all([
|
|
96
|
+
db.slaveMarketPlayer.findMany(),
|
|
97
|
+
db.slaveMarketTransaction.count(),
|
|
98
|
+
]);
|
|
99
|
+
const totalBalance = players.reduce((sum, p) => sum + p.balance, 0);
|
|
100
|
+
const totalDeposit = players.reduce((sum, p) => sum + p.deposit, 0);
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
const activeVips = players.filter((p) => p.vipEndTime && Number(p.vipEndTime) > now).length;
|
|
103
|
+
const yesterday = now - 24 * 60 * 60 * 1000;
|
|
104
|
+
const activePlayers24h = players.filter((p) => p.lastWorkTime && Number(p.lastWorkTime) > yesterday).length;
|
|
105
|
+
return {
|
|
106
|
+
totalPlayers: players.length,
|
|
107
|
+
totalTransactions: transactions,
|
|
108
|
+
totalBalance,
|
|
109
|
+
totalDeposit,
|
|
110
|
+
activeVips,
|
|
111
|
+
activePlayers24h,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 禁用/启用玩家命令
|
|
116
|
+
*/
|
|
117
|
+
async togglePlayerBan(targetId, banned) {
|
|
118
|
+
const db = getDatabase();
|
|
119
|
+
await db.slaveMarketPlayer.update({
|
|
120
|
+
where: { userId: targetId },
|
|
121
|
+
data: { commandBanned: banned },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 清理过期数据
|
|
126
|
+
*/
|
|
127
|
+
async cleanupExpiredData() {
|
|
128
|
+
const db = getDatabase();
|
|
129
|
+
const now = new Date();
|
|
130
|
+
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
131
|
+
const [redPackets, vipCards] = await Promise.all([
|
|
132
|
+
// 清理过期红包
|
|
133
|
+
db.slaveMarketRedPacket.deleteMany({
|
|
134
|
+
where: {
|
|
135
|
+
expiresAt: { lt: now },
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
// 清理已使用的旧卡密
|
|
139
|
+
db.slaveMarketVipCard.deleteMany({
|
|
140
|
+
where: {
|
|
141
|
+
used: true,
|
|
142
|
+
usedAt: { lt: thirtyDaysAgo },
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
]);
|
|
146
|
+
return {
|
|
147
|
+
redPackets: redPackets.count,
|
|
148
|
+
vipCards: vipCards.count,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 给玩家加钱
|
|
153
|
+
*/
|
|
154
|
+
async giveBalance(targetId, amount) {
|
|
155
|
+
const db = getDatabase();
|
|
156
|
+
const player = await db.slaveMarketPlayer.update({
|
|
157
|
+
where: { userId: targetId },
|
|
158
|
+
data: {
|
|
159
|
+
balance: { increment: amount },
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
return player.balance;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 银行服务 - 存款、取款、利息、贷款管理
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginContext } from '@napgram/sdk';
|
|
5
|
+
import { type SlaveMarketPlayer } from '../models';
|
|
6
|
+
import type { SlaveMarketConfig } from '../config';
|
|
7
|
+
import { TransactionService } from './transaction.service';
|
|
8
|
+
export declare class BankService {
|
|
9
|
+
private ctx;
|
|
10
|
+
private config;
|
|
11
|
+
private transactionService;
|
|
12
|
+
constructor(ctx: PluginContext, config: SlaveMarketConfig, transactionService: TransactionService);
|
|
13
|
+
/**
|
|
14
|
+
* 存款
|
|
15
|
+
*/
|
|
16
|
+
deposit(userId: string, amount: number): Promise<{
|
|
17
|
+
newDeposit: number;
|
|
18
|
+
newBalance: number;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* 取款
|
|
22
|
+
*/
|
|
23
|
+
withdraw(userId: string, amount: number): Promise<{
|
|
24
|
+
newDeposit: number;
|
|
25
|
+
newBalance: number;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* 计算利息
|
|
29
|
+
*/
|
|
30
|
+
calculateInterest(player: SlaveMarketPlayer): number;
|
|
31
|
+
/**
|
|
32
|
+
* 领取利息
|
|
33
|
+
*/
|
|
34
|
+
claimInterest(userId: string): Promise<{
|
|
35
|
+
interest: number;
|
|
36
|
+
newBalance: number;
|
|
37
|
+
hours: number;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* 升级信用等级
|
|
41
|
+
*/
|
|
42
|
+
upgradeCredit(userId: string): Promise<{
|
|
43
|
+
newLevel: number;
|
|
44
|
+
newLimit: number;
|
|
45
|
+
cost: number;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* 计算贷款额度
|
|
49
|
+
*/
|
|
50
|
+
calculateLoanLimit(player: SlaveMarketPlayer): number;
|
|
51
|
+
/**
|
|
52
|
+
* 申请贷款
|
|
53
|
+
*/
|
|
54
|
+
applyLoan(userId: string, amount: number): Promise<{
|
|
55
|
+
newLoanBalance: number;
|
|
56
|
+
newBalance: number;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* 还款
|
|
60
|
+
*/
|
|
61
|
+
repayLoan(userId: string, amount: number): Promise<{
|
|
62
|
+
newLoanBalance: number;
|
|
63
|
+
newBalance: number;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* 计算贷款利息
|
|
67
|
+
*/
|
|
68
|
+
calculateLoanInterest(player: SlaveMarketPlayer): number;
|
|
69
|
+
/**
|
|
70
|
+
* 累计贷款利息
|
|
71
|
+
*/
|
|
72
|
+
accrueLoanInterest(userId: string): Promise<SlaveMarketPlayer>;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=bank.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bank.service.d.ts","sourceRoot":"","sources":["../../src/services/bank.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAK3D,qBAAa,WAAW;IAEhB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;gBAFlB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,EAAE,kBAAkB;IAGlD;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACnD,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAuEF;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACpD,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAiEF;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;IAsBpD;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACzC,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC;IA6CF;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACzC,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC;IA2CF;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;IAMrD;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACrD,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IA2CF;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QACrD,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IA6CF;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;IAmBxD;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA6BvE"}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 银行服务 - 存款、取款、利息、贷款管理
|
|
3
|
+
*/
|
|
4
|
+
import { getDatabase } from '../models';
|
|
5
|
+
const HOUR_MS = 60 * 60 * 1000;
|
|
6
|
+
const MAX_INTEREST_HOURS = 24; // 最多累计24小时利息
|
|
7
|
+
export class BankService {
|
|
8
|
+
ctx;
|
|
9
|
+
config;
|
|
10
|
+
transactionService;
|
|
11
|
+
constructor(ctx, config, transactionService) {
|
|
12
|
+
this.ctx = ctx;
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.transactionService = transactionService;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 存款
|
|
18
|
+
*/
|
|
19
|
+
async deposit(userId, amount) {
|
|
20
|
+
const db = getDatabase();
|
|
21
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
22
|
+
if (!player) {
|
|
23
|
+
throw new Error('玩家不存在');
|
|
24
|
+
}
|
|
25
|
+
if (amount <= 0) {
|
|
26
|
+
throw new Error('存款金额必须大于0');
|
|
27
|
+
}
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
const interest = this.calculateInterest(player);
|
|
30
|
+
let balanceAfterInterest = player.balance;
|
|
31
|
+
if (interest > 0) {
|
|
32
|
+
balanceAfterInterest += interest;
|
|
33
|
+
}
|
|
34
|
+
if (balanceAfterInterest < amount) {
|
|
35
|
+
throw new Error('余额不足');
|
|
36
|
+
}
|
|
37
|
+
const newDeposit = player.deposit + amount;
|
|
38
|
+
if (newDeposit > player.depositLimit) {
|
|
39
|
+
throw new Error(`超过存款上限(${player.depositLimit}),请先升级信用等级`);
|
|
40
|
+
}
|
|
41
|
+
const result = await db.$transaction(async (tx) => {
|
|
42
|
+
if (interest > 0) {
|
|
43
|
+
await tx.slaveMarketTransaction.create({
|
|
44
|
+
data: {
|
|
45
|
+
userId,
|
|
46
|
+
type: 'interest',
|
|
47
|
+
amount: interest,
|
|
48
|
+
balance: balanceAfterInterest,
|
|
49
|
+
description: '存款利息结算',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const updated = await tx.slaveMarketPlayer.update({
|
|
54
|
+
where: { userId },
|
|
55
|
+
data: {
|
|
56
|
+
balance: balanceAfterInterest - amount,
|
|
57
|
+
deposit: newDeposit,
|
|
58
|
+
lastInterestTime: BigInt(now),
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
await tx.slaveMarketTransaction.create({
|
|
62
|
+
data: {
|
|
63
|
+
userId,
|
|
64
|
+
type: 'deposit',
|
|
65
|
+
amount: -amount,
|
|
66
|
+
balance: updated.balance,
|
|
67
|
+
description: '存款',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
return updated;
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
newDeposit: result.deposit,
|
|
74
|
+
newBalance: result.balance,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 取款
|
|
79
|
+
*/
|
|
80
|
+
async withdraw(userId, amount) {
|
|
81
|
+
const db = getDatabase();
|
|
82
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
83
|
+
if (!player) {
|
|
84
|
+
throw new Error('玩家不存在');
|
|
85
|
+
}
|
|
86
|
+
if (amount <= 0) {
|
|
87
|
+
throw new Error('取款金额必须大于0');
|
|
88
|
+
}
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
const interest = this.calculateInterest(player);
|
|
91
|
+
let balanceAfterInterest = player.balance;
|
|
92
|
+
if (interest > 0) {
|
|
93
|
+
balanceAfterInterest += interest;
|
|
94
|
+
}
|
|
95
|
+
if (player.deposit < amount) {
|
|
96
|
+
throw new Error('存款不足');
|
|
97
|
+
}
|
|
98
|
+
const result = await db.$transaction(async (tx) => {
|
|
99
|
+
if (interest > 0) {
|
|
100
|
+
await tx.slaveMarketTransaction.create({
|
|
101
|
+
data: {
|
|
102
|
+
userId,
|
|
103
|
+
type: 'interest',
|
|
104
|
+
amount: interest,
|
|
105
|
+
balance: balanceAfterInterest,
|
|
106
|
+
description: '存款利息结算',
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const updated = await tx.slaveMarketPlayer.update({
|
|
111
|
+
where: { userId },
|
|
112
|
+
data: {
|
|
113
|
+
balance: balanceAfterInterest + amount,
|
|
114
|
+
deposit: player.deposit - amount,
|
|
115
|
+
lastInterestTime: BigInt(now),
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
await tx.slaveMarketTransaction.create({
|
|
119
|
+
data: {
|
|
120
|
+
userId,
|
|
121
|
+
type: 'withdraw',
|
|
122
|
+
amount,
|
|
123
|
+
balance: updated.balance,
|
|
124
|
+
description: '取款',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
return updated;
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
newDeposit: result.deposit,
|
|
131
|
+
newBalance: result.balance,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 计算利息
|
|
136
|
+
*/
|
|
137
|
+
calculateInterest(player) {
|
|
138
|
+
if (player.deposit <= 0) {
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
const lastTime = player.lastInterestTime ? Number(player.lastInterestTime) : Date.now();
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
const elapsedHours = Math.min(Math.floor((now - lastTime) / HOUR_MS), MAX_INTEREST_HOURS);
|
|
144
|
+
if (elapsedHours <= 0) {
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
const rate = this.config.存款利率;
|
|
148
|
+
const interest = Math.floor(player.deposit * rate * elapsedHours);
|
|
149
|
+
return interest;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 领取利息
|
|
153
|
+
*/
|
|
154
|
+
async claimInterest(userId) {
|
|
155
|
+
const db = getDatabase();
|
|
156
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
157
|
+
if (!player) {
|
|
158
|
+
throw new Error('玩家不存在');
|
|
159
|
+
}
|
|
160
|
+
const interest = this.calculateInterest(player);
|
|
161
|
+
if (interest <= 0) {
|
|
162
|
+
throw new Error('当前没有可领取的利息');
|
|
163
|
+
}
|
|
164
|
+
const lastTime = player.lastInterestTime ? Number(player.lastInterestTime) : Date.now();
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
const hours = Math.min(Math.floor((now - lastTime) / HOUR_MS), MAX_INTEREST_HOURS);
|
|
167
|
+
const result = await db.slaveMarketPlayer.update({
|
|
168
|
+
where: { userId },
|
|
169
|
+
data: {
|
|
170
|
+
balance: player.balance + interest,
|
|
171
|
+
lastInterestTime: BigInt(now),
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
// 记录交易
|
|
175
|
+
await this.transactionService.createTransaction({
|
|
176
|
+
userId,
|
|
177
|
+
type: 'interest',
|
|
178
|
+
amount: interest,
|
|
179
|
+
balance: result.balance,
|
|
180
|
+
description: `利息(${hours}小时)`,
|
|
181
|
+
});
|
|
182
|
+
return {
|
|
183
|
+
interest,
|
|
184
|
+
newBalance: result.balance,
|
|
185
|
+
hours,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 升级信用等级
|
|
190
|
+
*/
|
|
191
|
+
async upgradeCredit(userId) {
|
|
192
|
+
const db = getDatabase();
|
|
193
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
194
|
+
if (!player) {
|
|
195
|
+
throw new Error('玩家不存在');
|
|
196
|
+
}
|
|
197
|
+
const currentLevel = player.creditLevel;
|
|
198
|
+
const cost = Math.floor(1000 * Math.pow(2, currentLevel - 1));
|
|
199
|
+
if (player.balance < cost) {
|
|
200
|
+
throw new Error(`升级需要 ${cost} 金币,当前余额不足`);
|
|
201
|
+
}
|
|
202
|
+
const newLevel = currentLevel + 1;
|
|
203
|
+
const newLimit = Math.floor(this.config.初始存款上限 * Math.pow(2, newLevel - 1));
|
|
204
|
+
const result = await db.slaveMarketPlayer.update({
|
|
205
|
+
where: { userId },
|
|
206
|
+
data: {
|
|
207
|
+
balance: player.balance - cost,
|
|
208
|
+
creditLevel: newLevel,
|
|
209
|
+
depositLimit: newLimit,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
// 记录交易
|
|
213
|
+
await this.transactionService.createTransaction({
|
|
214
|
+
userId,
|
|
215
|
+
type: 'system',
|
|
216
|
+
amount: -cost,
|
|
217
|
+
balance: result.balance,
|
|
218
|
+
description: `升级信用等级至 ${newLevel}`,
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
newLevel,
|
|
222
|
+
newLimit,
|
|
223
|
+
cost,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 计算贷款额度
|
|
228
|
+
*/
|
|
229
|
+
calculateLoanLimit(player) {
|
|
230
|
+
const { 基础额度, 等级加成 } = this.config.贷款系统;
|
|
231
|
+
const level = player.loanCreditLevel || 1;
|
|
232
|
+
return Math.floor(基础额度 + (level - 1) * 等级加成);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 申请贷款
|
|
236
|
+
*/
|
|
237
|
+
async applyLoan(userId, amount) {
|
|
238
|
+
const db = getDatabase();
|
|
239
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
240
|
+
if (!player) {
|
|
241
|
+
throw new Error('玩家不存在');
|
|
242
|
+
}
|
|
243
|
+
if (amount <= 0) {
|
|
244
|
+
throw new Error('贷款金额必须大于0');
|
|
245
|
+
}
|
|
246
|
+
const limit = this.calculateLoanLimit(player);
|
|
247
|
+
const available = limit - player.loanBalance;
|
|
248
|
+
if (amount > available) {
|
|
249
|
+
throw new Error(`可用额度不足,当前可贷: ${available}`);
|
|
250
|
+
}
|
|
251
|
+
const result = await db.slaveMarketPlayer.update({
|
|
252
|
+
where: { userId },
|
|
253
|
+
data: {
|
|
254
|
+
balance: player.balance + amount,
|
|
255
|
+
loanBalance: player.loanBalance + amount,
|
|
256
|
+
lastLoanInterestTime: BigInt(Date.now()),
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
// 记录交易
|
|
260
|
+
await this.transactionService.createTransaction({
|
|
261
|
+
userId,
|
|
262
|
+
type: 'loan',
|
|
263
|
+
amount,
|
|
264
|
+
balance: result.balance,
|
|
265
|
+
description: '贷款',
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
newLoanBalance: result.loanBalance,
|
|
269
|
+
newBalance: result.balance,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 还款
|
|
274
|
+
*/
|
|
275
|
+
async repayLoan(userId, amount) {
|
|
276
|
+
const db = getDatabase();
|
|
277
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
278
|
+
if (!player) {
|
|
279
|
+
throw new Error('玩家不存在');
|
|
280
|
+
}
|
|
281
|
+
if (amount <= 0) {
|
|
282
|
+
throw new Error('还款金额必须大于0');
|
|
283
|
+
}
|
|
284
|
+
if (player.loanBalance <= 0) {
|
|
285
|
+
throw new Error('当前没有贷款');
|
|
286
|
+
}
|
|
287
|
+
const actualAmount = Math.min(amount, player.loanBalance);
|
|
288
|
+
if (player.balance < actualAmount) {
|
|
289
|
+
throw new Error('余额不足');
|
|
290
|
+
}
|
|
291
|
+
const result = await db.slaveMarketPlayer.update({
|
|
292
|
+
where: { userId },
|
|
293
|
+
data: {
|
|
294
|
+
balance: player.balance - actualAmount,
|
|
295
|
+
loanBalance: player.loanBalance - actualAmount,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
// 记录交易
|
|
299
|
+
await this.transactionService.createTransaction({
|
|
300
|
+
userId,
|
|
301
|
+
type: 'repay',
|
|
302
|
+
amount: -actualAmount,
|
|
303
|
+
balance: result.balance,
|
|
304
|
+
description: '还款',
|
|
305
|
+
});
|
|
306
|
+
return {
|
|
307
|
+
newLoanBalance: result.loanBalance,
|
|
308
|
+
newBalance: result.balance,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* 计算贷款利息
|
|
313
|
+
*/
|
|
314
|
+
calculateLoanInterest(player) {
|
|
315
|
+
if (player.loanBalance <= 0) {
|
|
316
|
+
return 0;
|
|
317
|
+
}
|
|
318
|
+
const lastTime = player.lastLoanInterestTime ? Number(player.lastLoanInterestTime) : Date.now();
|
|
319
|
+
const now = Date.now();
|
|
320
|
+
const elapsedHours = Math.floor((now - lastTime) / HOUR_MS);
|
|
321
|
+
if (elapsedHours <= 0) {
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
324
|
+
const rate = this.config.贷款系统.利率;
|
|
325
|
+
const interest = Math.max(1, Math.floor(player.loanBalance * rate * elapsedHours));
|
|
326
|
+
return interest;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 累计贷款利息
|
|
330
|
+
*/
|
|
331
|
+
async accrueLoanInterest(userId) {
|
|
332
|
+
const db = getDatabase();
|
|
333
|
+
const player = await db.slaveMarketPlayer.findUnique({ where: { userId } });
|
|
334
|
+
if (!player || player.loanBalance <= 0) {
|
|
335
|
+
return player;
|
|
336
|
+
}
|
|
337
|
+
const interest = this.calculateLoanInterest(player);
|
|
338
|
+
if (interest <= 0) {
|
|
339
|
+
return player;
|
|
340
|
+
}
|
|
341
|
+
const lastTime = player.lastLoanInterestTime ? Number(player.lastLoanInterestTime) : Date.now();
|
|
342
|
+
const now = Date.now();
|
|
343
|
+
const elapsedHours = Math.floor((now - lastTime) / HOUR_MS);
|
|
344
|
+
const nextTime = lastTime + elapsedHours * HOUR_MS;
|
|
345
|
+
const result = await db.slaveMarketPlayer.update({
|
|
346
|
+
where: { userId },
|
|
347
|
+
data: {
|
|
348
|
+
loanBalance: player.loanBalance + interest,
|
|
349
|
+
lastLoanInterestTime: BigInt(nextTime),
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
return result;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 保镖服务 - 雇佣保镖、防护管理
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginContext } from '@napgram/sdk';
|
|
5
|
+
import type { SlaveMarketConfig } from '../config';
|
|
6
|
+
import { TransactionService } from './transaction.service';
|
|
7
|
+
import type { Bodyguard } from '../types';
|
|
8
|
+
export declare const BODYGUARDS: Bodyguard[];
|
|
9
|
+
export declare class BodyguardService {
|
|
10
|
+
private ctx;
|
|
11
|
+
private config;
|
|
12
|
+
private transactionService;
|
|
13
|
+
constructor(ctx: PluginContext, config: SlaveMarketConfig, transactionService: TransactionService);
|
|
14
|
+
/**
|
|
15
|
+
* 获取保镖信息
|
|
16
|
+
*/
|
|
17
|
+
getBodyguard(name: string): Bodyguard | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* 雇佣保镖
|
|
20
|
+
*/
|
|
21
|
+
hireBodyguard(userId: string, bodyguardName: string, isAdmin?: boolean): Promise<{
|
|
22
|
+
cost: number;
|
|
23
|
+
duration: number;
|
|
24
|
+
endTime: number;
|
|
25
|
+
newBalance: number;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* 检查保镖是否有效
|
|
29
|
+
*/
|
|
30
|
+
hasActiveBodyguard(userId: string): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* 格式化保镖列表
|
|
33
|
+
*/
|
|
34
|
+
formatBodyguardList(): string;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=bodyguard.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyguard.service.d.ts","sourceRoot":"","sources":["../../src/services/bodyguard.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,eAAO,MAAM,UAAU,EAAE,SAAS,EAKjC,CAAC;AAEF,qBAAa,gBAAgB;IAErB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;gBAFlB,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,EAAE,kBAAkB;IAGlD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIjD;;OAEG;IACG,aAAa,CACf,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,OAAe,GACzB,OAAO,CAAC;QACP,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IAwDF;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW1D;;OAEG;IACH,mBAAmB,IAAI,MAAM;CAehC"}
|