diff --git a/README.md b/README.md index e923a77fdc..e88ef9adf1 100644 --- a/README.md +++ b/README.md @@ -520,6 +520,34 @@ print("run[CQ:image,file="+j["img"]+"]") 检测类型编号列表:[1:违禁违规|2:文本色情|3:敏感信息|4:恶意推广|5:低俗辱骂|6:恶意推广-联系方式|7:恶意推广-软文推广] + +
+ bank + + `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bank"` + + - [x] 银行活期存款 [金额] + + - [x] 银行定期存款 [金额] [期限(3/7/15/30天)] + + - [x] 银行活期取款 [金额/全部] + + - [x] 银行定期取款 [全部] [定期款序列号] + + - [x] 银行贷款 [金额] [期限(天)] + + - [x] 银行还款 [金额] + + - [x] 查看我的存款 + + - [x] 查看我的贷款 + + - [x] 查看今日利率 + + - [x] 我要信仰之跃 + +
+
base64卦加解密 diff --git a/main.go b/main.go index 4de143cfcc..8751f04523 100644 --- a/main.go +++ b/main.go @@ -73,6 +73,7 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace" // AnimeTrace 动画/Galgame识别 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/autowithdraw" // 触发者撤回时也自动撤回 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核 + _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bank" // 银行 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/base16384" // base16384加解密 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密 diff --git a/plugin/bank/bank.go b/plugin/bank/bank.go new file mode 100644 index 0000000000..5fcf5a5754 --- /dev/null +++ b/plugin/bank/bank.go @@ -0,0 +1,537 @@ +// Package bank 银行 +package bank + +import ( + "os" + "strconv" + "time" + "math/rand" + "math" + "fmt" + + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/AnimeAPI/wallet" + "gopkg.in/yaml.v3" +) + +func init() { + // 初始化数据目录 + _ = os.MkdirAll(accountPath, 0755) + + // 加载账户数据 + loadAllAccounts() + + // 加载利息信息 + loadInterestInfo() + + // 启动定时任务 + initCronJobs() + + // 检查贷款是否逾期 + processLoanOverdue() + + // 添加自动扣款任务 + autoDeductLoanPayment() +} + +// 修改initCronJobs函数,添加自动扣款调用 +func initCronJobs() { + go func() { + for { + now := time.Now() + nextDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(24 * time.Hour) + time.Sleep(nextDay.Sub(now)) + + // 每日任务 + calculateDailyCurrentInterest() + processMatureFixedDeposits() + processLoanOverdue() + autoDeductLoanPayment() // 添加自动扣款任务 + cleanupAllExpiredBuffs() // 每日清理所有用户的过期buff + } + }() +} + +// GetOrCreateAccount 获取或创建账户 +func GetOrCreateAccount(uid int64) *Account { + account, ok := accounts[uid] + if !ok { + account = &Account{ + UserID: uid, + CurrentBalance: 0, + FixedDeposits: []FixedDeposit{}, + Loans: []Loan{}, + LastUpdate: time.Now(), + } + accounts[uid] = account + } + return account +} + +// 加载所有账户数据 +func loadAllAccounts() { + files, err := os.ReadDir(accountPath) + if err != nil { + return + } + for _, f := range files { + if f.IsDir() { + continue + } + uid, err := strconv.ParseInt(f.Name(), 10, 64) + if err != nil { + continue + } + data, err := os.ReadFile(accountPath + f.Name()) + if err != nil { + continue + } + var account Account + if err := yaml.Unmarshal(data, &account); err != nil { + continue + } + accounts[uid] = &account + } +} + +// SaveAccount 保存账户信息 +func SaveAccount(account *Account) error { + data, err := yaml.Marshal(account) + if err != nil { + return err + } + return os.WriteFile(accountPath+strconv.FormatInt(account.UserID, 10), data, 0644) +} + +// 检查并更新今日利率 +func checkAndUpdateInterest() { + today := time.Now().Format("2006-01-02") + if dailyInterest.LastDate != today { + rateRange := CurrentRateMax - CurrentRateMin // 计算利率范围 + // 每天随机生成活期利率(1% - 3%) + dailyInterest.CurrentRate = CurrentRateMin + rand.Float64()*rateRange + dailyInterest.LastDate = today + data, _ := yaml.Marshal(dailyInterest) + _ = os.WriteFile(interestPath, data, 0644) + } +} + +// 计算每日活期利息 +func calculateDailyCurrentInterest() { + now := time.Now() + for _, account := range accounts { + if account.CurrentBalance <= 0 { + continue + } + + // 基础利率 + rate := dailyInterest.CurrentRate + + // 重生用户活期利率下调 + stacks := getRebirthStacks(account) + if stacks > 0 { + rate *= (1 - CurrentRateDecreasePercent*float64(stacks)) + } + + interest := int(float64(account.CurrentBalance) * rate) + if interest > 0 { + account.CurrentBalance += interest + account.LastUpdate = now + _ = SaveAccount(account) + } + } +} + +// 加载利息信息 +func loadInterestInfo() { + if !file.IsExist(interestPath) { + // 检查 saveInterestInfo 的错误返回值 + if err := saveInterestInfo(); err != nil { + fmt.Printf("加载利息信息失败:首次创建利息文件时出错 - %v", err) + return + } + return + } + + data, err := os.ReadFile(interestPath) + if err != nil { + fmt.Printf("读取利息信息文件失败:%v", err) // 补充错误日志 + return + } + + // 检查 yaml 解析错误 + if err := yaml.Unmarshal(data, dailyInterest); err != nil { + fmt.Printf("解析利息信息失败:%v", err) + } +} + +// 保存利息信息 +func saveInterestInfo() error { + data, err := yaml.Marshal(dailyInterest) + if err != nil { + return err + } + return os.WriteFile(interestPath, data, 0644) +} + +// 处理到期的定期存款 +func processMatureFixedDeposits() { + now := time.Now() + for _, account := range accounts { + matureIndex := -1 + for i, fd := range account.FixedDeposits { + if now.After(fd.MaturityDate) || now.Equal(fd.MaturityDate) { + matureIndex = i + break + } + } + if matureIndex != -1 { + // 取出到期存款及利息 + fd := account.FixedDeposits[matureIndex] + interest := int(float64(fd.Amount) * fd.Rate / 100) + account.CurrentBalance += fd.Amount + interest + // 移除到期存款 + account.FixedDeposits = append(account.FixedDeposits[:matureIndex], account.FixedDeposits[matureIndex+1:]...) + account.LastUpdate = now + _ = SaveAccount(account) + } + } +} + +// CalculateTotalCurrentDeposits 计算银行总活期存款 +func CalculateTotalCurrentDeposits() (total int) { + for _, account := range accounts { + total += account.CurrentBalance + } + return +} + +// CalculateTotalFixedDeposits 计算银行总定期存款 +func CalculateTotalFixedDeposits() (total int) { + for _, account := range accounts { + for _, fd := range account.FixedDeposits { + total += fd.Amount + } + } + return +} + +// CalculateTotalLoans 计算银行总贷款(未还清的贷款总额) +func CalculateTotalLoans() (total float64) { + for _, account := range accounts { + for _, loan := range account.Loans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + // 累加未还清部分 + if loan.RepaidAmount < totalRepay { + total += totalRepay - loan.RepaidAmount + } + } + } + return +} + +// HasActiveLoan 检查是否有未还清的贷款 +func HasActiveLoan(account *Account) bool { + for _, loan := range account.Loans { + if loan.RepaidAmount < loan.Amount { + return true + } + } + return false +} + +// 计算贷款应还总额 +func calculateLoanRepay(amount, rate float64, termDays int) float64 { + dailyRate := rate / 100 + interest := amount * dailyRate * float64(termDays) + return amount + interest +} + +// 处理逾期贷款 +func autoDeductLoanPayment() { + now := time.Now() + for _, account := range accounts { + // 只收集逾期且未还清的贷款 + var overdueLoans []int // 仅处理逾期贷款 + + // 筛选条件:必须是逾期状态(IsOverdue=true)且有未还清金额 + for i, loan := range account.Loans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + remaining := totalRepay - float64(loan.RepaidAmount) + + // 仅处理:逾期 + 未还清的贷款 + if loan.IsOverdue && remaining > 0 { + overdueLoans = append(overdueLoans, i) + } + // 非逾期贷款:直接跳过,不做任何处理 + } + + // 只对逾期且未还清的贷款执行自动扣款 + for _, i := range overdueLoans { + deductOverdueLoan(account, i, now) + } + } +} + +// 处理贷款逾期 +func processLoanOverdue() { + now := time.Now() + for _, account := range accounts { + for i := range account.Loans { + loan := &account.Loans[i] + // 计算到期日 + maturityDate := loan.StartDate.AddDate(0, 0, loan.TermDays) + // 检查是否逾期 + if now.After(maturityDate) && !loan.IsOverdue { + loan.IsOverdue = true + account.LastUpdate = now + _ = SaveAccount(account) + } + } + } +} + +// 专门处理逾期贷款的扣款逻辑 +func deductOverdueLoan(account *Account, loanIndex int, now time.Time) { + loan := &account.Loans[loanIndex] + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + remaining := totalRepay - float64(loan.RepaidAmount) + + // 安全校验:确保是逾期且未还清状态 + if !loan.IsOverdue || remaining <= 0 { + return + } + + needDeduct := remaining + fmt.Printf("[逾期自动扣款] 用户%d的逾期贷款开始扣款,剩余应还: %.2f", account.UserID, needDeduct) + + // 1. 从钱包扣款 + walletBalance := float64(wallet.GetWalletOf(account.UserID)) + if walletBalance > 0 { + deduct := math.Min(needDeduct, walletBalance) + _ = wallet.InsertWalletOf(account.UserID, -int(math.Round(deduct))) + loan.RepaidAmount += float64(int(math.Round(deduct))) + needDeduct -= deduct + fmt.Printf("[逾期自动扣款] 从钱包扣除: %.2f,剩余: %.2f", deduct, needDeduct) + } + + if needDeduct <= 0 { + account.LastUpdate = now + _ = SaveAccount(account) + fmt.Printf("[逾期自动扣款] 用户%d的逾期贷款已还清", account.UserID) + cleanupCompletedLoans(account) // 清理已还清的逾期贷款记录 + return + } + + // 2. 从活期存款扣款 + if account.CurrentBalance > 0 { + deduct := math.Min(needDeduct, float64(account.CurrentBalance)) + account.CurrentBalance -= int(math.Round(deduct)) + loan.RepaidAmount += deduct + needDeduct -= deduct + fmt.Printf("[逾期自动扣款] 从活期扣除: %.2f,剩余: %.2f", deduct, needDeduct) + } + + if needDeduct <= 0 { + account.LastUpdate = now + _ = SaveAccount(account) + fmt.Printf("[逾期自动扣款] 用户%d的逾期贷款已还清", account.UserID) + cleanupCompletedLoans(account) + return + } + + // 3. 从定期存款扣款(逾期贷款手续费70%) + feeRate := 0.7 // 固定为逾期的高手续费率 + for len(account.FixedDeposits) > 0 && needDeduct > 0 { + fd := &account.FixedDeposits[0] + available := float64(fd.Amount) * (1 - feeRate) // 扣除手续费后的可用金额 + + deduct := math.Min(needDeduct, available) + loan.RepaidAmount += deduct + needDeduct -= deduct + + // 计算实际消耗的定期本金(含手续费) + usedPrincipal := int(math.Ceil(deduct / (1 - feeRate))) + fmt.Printf("[逾期自动扣款] 从定期扣除: %.2f(本金消耗: %d,手续费率: 70%%)", deduct, usedPrincipal) + + // 更新定期存款记录 + if usedPrincipal >= fd.Amount { + account.FixedDeposits = account.FixedDeposits[1:] // 全额取出 + } else { + fd.Amount -= usedPrincipal // 部分取出 + } + } + + // 最终处理 + account.LastUpdate = now + if err := SaveAccount(account); err != nil { + fmt.Printf("[逾期自动扣款] 保存用户%d账户失败: %v", account.UserID, err) + } else if needDeduct > 0 { + fmt.Printf("[逾期自动扣款] 用户%d的逾期贷款仍有剩余: %.2f", account.UserID, needDeduct) + } else { + fmt.Printf("[逾期自动扣款] 用户%d的逾期贷款已还清", account.UserID) + cleanupCompletedLoans(account) + } +} + + +// 清理账户中已完成的贷款记录 +func cleanupCompletedLoans(account *Account) { + filteredLoans := []Loan{} + for _, loan := range account.Loans { + // 保留未还清的贷款(已还金额 < 应还总额) + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + if loan.RepaidAmount < totalRepay { + filteredLoans = append(filteredLoans, loan) + } + } + // 更新贷款列表(删除已完成记录) + account.Loans = filteredLoans +} + +// 检查用户是否无力偿还贷款(钱包为零+银行存款为零+有未还清贷款) +func hasUnpayableLoan(account *Account) bool { + // 钱包余额判断 + walletBalance := wallet.GetWalletOf(account.UserID) + if walletBalance != 0 { + return false + } + + // 银行存款判断(活期 + 定期都要为 0) + if account.CurrentBalance != 0 { + return false + } + for _, fd := range account.FixedDeposits { + if fd.Amount > 0 { + return false + } + } + + // 未还清贷款判断 + for _, loan := range account.Loans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + if totalRepay - float64(loan.RepaidAmount) > 0 { + return true // 存在未还清贷款 + } + } + return false // 无未还清贷款 +} + +// 执行信仰之跃重生 +func applyRebirth(account *Account) { + // 1. 清零所有贷款 + account.Loans = []Loan{} + + // 2. (可选)清理已完成的贷款(如果有) + cleanupCompletedLoans(account) + + // 3. 不添加任何 buff!(buff 由 addRebirthBuff 单独处理) +} + +// 获取重生buff的有效层数 +func getRebirthStacks(account *Account) int { + now := time.Now() + stacks := 0 + for _, buff := range account.Buffs { + // 直接通过 Buff.Name 判断,无需额外转换 + if buff.Name == RebirthBuffName && now.Before(buff.ExpireTime) { + stacks++ + } + } + // 限制最大层数 + if stacks > MaxRebirthStack { + return MaxRebirthStack + } + return stacks +} + +// 向账户添加重生buff(自动处理叠加和过期) +func addRebirthBuff(account *Account) { + now := time.Now() + // 先清理过期buff,避免无效数据干扰 + cleanupExpiredBuffs(account) + + currentStacks := getRebirthStacks(account) + newBuff := Buff{ + Name: RebirthBuffName, + ExpireTime: now.Add(RebirthBuffDuration), // 7天后过期 + } + + if currentStacks < MaxRebirthStack { + // 未达上限,直接添加新buff + account.Buffs = append(account.Buffs, newBuff) + } else { + // 已达上限,替换最早过期的buff + earliestIndex := 0 + earliestTime := account.Buffs[0].ExpireTime + for i, buff := range account.Buffs { + if buff.Name == RebirthBuffName && buff.ExpireTime.Before(earliestTime) { + earliestIndex = i + earliestTime = buff.ExpireTime + } + } + account.Buffs[earliestIndex] = newBuff + } +} + +// 清理账户中所有过期的重生buff +func cleanupExpiredBuffs(account *Account) { + now := time.Now() + validBuffs := []Buff{} + for _, buff := range account.Buffs { + if now.Before(buff.ExpireTime) { // 保留未过期的buff + validBuffs = append(validBuffs, buff) + } + } + account.Buffs = validBuffs +} + +// 清理所有用户的过期buff +func cleanupAllExpiredBuffs() { + now := time.Now() + for _, account := range accounts { + originalCount := len(account.Buffs) + cleanupExpiredBuffs(account) + // 若buff数量有变化,保存更新 + if len(account.Buffs) != originalCount { + account.LastUpdate = now + _ = SaveAccount(account) + } + } +} + +// 计算最早过期的重生buff剩余时间 +func getEarliestRebirthBuffExpiry(account *Account) (time.Duration, bool) { + now := time.Now() + var earliestExpiry time.Time + + // 遍历所有buff,筛选出重生buff(通过 Buff.Name 判断) + for _, buff := range account.Buffs { + if buff.Name == RebirthBuffName { // 直接使用 Buff 结构体的 Name 字段 + // 记录最早过期的重生buff + if earliestExpiry.IsZero() || buff.ExpireTime.Before(earliestExpiry) { + earliestExpiry = buff.ExpireTime // 直接使用 Buff 结构体的 ExpireTime 字段 + } + } + } + + if earliestExpiry.IsZero() { + return 0, false // 无有效重生buff + } + + // 计算剩余时间(若已过期则返回0) + if earliestExpiry.Before(now) { + return 0, true + } + return earliestExpiry.Sub(now), true +} + +// 格式化时间间隔为"X小时Y分钟" +func formatDuration(d time.Duration) string { + if d <= 0 { + return "已过期" + } + hours := int(d.Hours()) + minutes := int(d.Minutes()) % 60 + return fmt.Sprintf("%d小时%d分钟", hours, minutes) +} \ No newline at end of file diff --git a/plugin/bank/main.go b/plugin/bank/main.go new file mode 100644 index 0000000000..4fd15f85cd --- /dev/null +++ b/plugin/bank/main.go @@ -0,0 +1,840 @@ +// Package bank 银行 +package bank + +import ( + "strconv" + "strings" + "time" + "fmt" + "math" + "sort" + "regexp" + + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/zbputils/ctxext" + zero "github.com/wdvxdr1123/ZeroBot" + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" + "github.com/wdvxdr1123/ZeroBot/message" +) + +// 活期利率范围(1% - 3%) +const ( + CurrentRateMin = 0.01 // 最小活期利率 + CurrentRateMax = 0.03 // 最大活期利率 +) + +// 定期存款利率表(根据期限不同) +var fixedDepositRates = map[int]float64{ + 3: 0.1, // 3 天期, 利率 10% + 7: 0.36, // 7 天期, 利率 36% + 15: 1, // 15 天期,利率 100% + 30: 3, // 30 天期,利率 300% +} + +// LoanDailyRate 贷款日利率 +const LoanDailyRate = 25 + +// 重生用户利率调整比例(百分比) +const ( + // 活期存款利率下调比例(例如0.1表示下调10%) + CurrentRateDecreasePercent = 0.1 + // 定期存款利率下调比例 + FixedRateDecreasePercent = 0.1 + // 贷款利率上调比例 + LoanRateIncreasePercent = 0.5 + // 可贷款金额上调比例 + LoanAmountIncreasePercent = 0.5 + // 基础可贷款金额上限 + BaseMaxLoanAmount = 20000 +) + +const ( + // RebirthBuffName 重生buff的名称 + RebirthBuffName = "rebirth" + // MaxRebirthStack buff最大能叠加的次数 + MaxRebirthStack = 3 + // RebirthBuffDuration 每层buff的持续时间 + RebirthBuffDuration = 7 * 24 * time.Hour +) + +var ( + // 注册插件引擎 + engine = control.Register("bank", &ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Brief: "银行", + Help: "- 银行活期存款 [金额/全部] (活期利率每天都会在1%~3%波动)\n" + + "- 银行定期存款 [金额] [期限(3/7/15/30天)]\n" + + "- 银行活期取款 [金额/全部] \n" + + "- 银行定期取款 [全部] [定期款序列号] \n" + + "- 银行贷款 [金额] [期限(天)](到了还款日后会强制还款哦~)\n" + + "- 银行还款 [金额]\n" + + "- 查看我的存款\n" + + "- 查看我的贷款\n" + + "- 查看今日利率\n" + + "- 我要信仰之跃\n", + PrivateDataFolder: "bank", + }) + + accountPath = engine.DataFolder() + "accounts/" + interestPath = engine.DataFolder() + "interest.yaml" + accounts = make(map[int64]*Account) // 内存中的账户数据 + dailyInterest = &InterestInfo{CurrentRate: 0.01} // 默认活期利率 1% +) + +var numRegex = regexp.MustCompile(`\d+`) + +func init() { + // 银行活期存款命令处理 + engine.OnPrefix("银行活期存款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + param := strings.TrimSpace(ctx.State["args"].(string)) + if param == "" { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请输入存款金额,例如:银行活期存款 100 或 银行活期存款 全部")) + return + } + + uid := ctx.Event.UserID + var amount int + var err error + + // 处理“全部”存款的情况 + if param == "全部" { + amount = wallet.GetWalletOf(uid) // 获取钱包全部余额 + } else { + // 原逻辑:提取数字金额 + numStr := numRegex.FindString(param) + if numStr == "" { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("输入的金额无效,请输入正整数或'全部',例如:100 或 全部")) + return + } + amount, err = strconv.Atoi(numStr) + if err != nil || amount <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("输入的金额无效,请输入正整数或'全部'")) + return + } + } + + // 检查金额有效性(钱包余额是否足够) + if wallet.GetWalletOf(uid) < amount { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("钱包余额不足,无法存款")) + return + } + if amount <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("存款金额必须大于0")) + return + } + + // 执行存款操作(扣除钱包金额,增加活期余额) + err = wallet.InsertWalletOf(uid, -amount) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("存款失败:", err)) + return + } + + account := GetOrCreateAccount(uid) + account.CurrentBalance += amount + account.LastUpdate = time.Now() + _ = SaveAccount(account) + + stacks := getRebirthStacks(account) + currentBaseRate := dailyInterest.CurrentRate + actualRate := currentBaseRate + rateDesc := "" + if stacks > 0 { + actualRate *= (1 - CurrentRateDecreasePercent*float64(stacks)) + rateDesc = fmt.Sprintf("(重生buff x%d生效,基础利率下调%.0f%%)", + stacks, CurrentRateDecreasePercent*float64(stacks)*100) + } + + rateInfo := fmt.Sprintf( + "活期基础利率:%.2f%%/天\n你的实际利率:%.2f%%/天%s", + currentBaseRate*100, + actualRate*100, + rateDesc, + ) + + walletBalance := wallet.GetWalletOf(uid) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text( + fmt.Sprintf( + "活期存款成功!\n当前活期余额:%d%s\n当前钱包余额:%d%s\n%s\n当前重生buff: %d/%d层", + account.CurrentBalance, + wallet.GetWalletName(), + walletBalance, + wallet.GetWalletName(), + rateInfo, + stacks, + MaxRebirthStack, + ), + )) + }) + // 银行定期存款命令处理 + engine.OnPrefix("银行定期存款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + params := strings.Fields(strings.TrimSpace(ctx.State["args"].(string))) + if len(params) < 2 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("格式错误!示例:银行定期存款 1000 3(存款1000,期限3天)")) + return + } + + amount, err := strconv.Atoi(params[0]) + term, errTerm := strconv.Atoi(params[1]) + if err != nil || errTerm != nil || amount <= 0 || term <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("金额或期限无效,请输入正整数!")) + return + } + + baseRate, exists := fixedDepositRates[term] + if !exists { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("不支持的存款期限,支持的期限:3、7、15、30天")) + return + } + + uid := ctx.Event.UserID + if wallet.GetWalletOf(uid) < amount { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("钱包余额不足,无法存款")) + return + } + + err = wallet.InsertWalletOf(uid, -amount) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("存款失败:", err)) + return + } + + account := GetOrCreateAccount(uid) + stacks := getRebirthStacks(account) + + actualRate := baseRate + rateAdjustDesc := "" + if stacks > 0 { + actualRate *= (1 - FixedRateDecreasePercent*float64(stacks)) + rateAdjustDesc = fmt.Sprintf("(重生buff x%d生效,利率基础下调%.0f%%)", + stacks, FixedRateDecreasePercent*float64(stacks)*100) + } + + interest := float64(amount) * actualRate + totalAmount := float64(amount) + interest + + rateInfo := fmt.Sprintf( + "基础利率:%.2f%%\n实际利率:%.2f%%%s", + baseRate*100, + actualRate*100, + rateAdjustDesc, + ) + + now := time.Now() + fixedDeposit := FixedDeposit{ + Amount: amount, + TermDays: term, + Rate: actualRate, + StartDate: now, + MaturityDate: now.AddDate(0, 0, term), + } + + account.FixedDeposits = append(account.FixedDeposits, fixedDeposit) + account.LastUpdate = now + if err := SaveAccount(account); err != nil { + // 错误处理逻辑:记录错误日志 + fmt.Printf("保存账户失败: %v", err) + return + } + + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf( + "定期存款成功!\n金额:%d%s\n期限:%d天\n%s\n可得利息:%.2f%s\n可得总资金(本金+利息):%.2f%s\n到期日:%s\n当前重生buff: %d/%d层", + amount, wallet.GetWalletName(), + term, + rateInfo, + interest, wallet.GetWalletName(), + totalAmount, wallet.GetWalletName(), + fixedDeposit.MaturityDate.Format("2006-01-02"), + stacks, + MaxRebirthStack, + ))) + }) + + // 银行活期取款 + engine.OnPrefix("银行活期取款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + params := strings.Fields(strings.TrimSpace(ctx.State["args"].(string))) + if len(params) < 1 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请输入取款金额,例如:\n银行活期取款 100\n银行活期取款 全部")) + return + } + + amountStr := params[0] + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + var amount int + var err error + + if amountStr == "全部" { + amount = account.CurrentBalance + } else { + amount, err = strconv.Atoi(amountStr) + if err != nil || amount <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("输入的金额无效,请输入正整数或'全部'")) + return + } + } + + if account.CurrentBalance < amount { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("活期余额不足,无法取款")) + return + } + + account.CurrentBalance -= amount + account.LastUpdate = time.Now() + if err := SaveAccount(account); err != nil { + fmt.Printf("更新账户保存失败: %v", err) + return + } + + err = wallet.InsertWalletOf(uid, amount) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("取款失败:", err)) + return + } + + walletBalance := wallet.GetWalletOf(uid) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text( + fmt.Sprintf( + "活期取款成功!\n当前活期余额:%d%s\n当前钱包余额:%d%s", + account.CurrentBalance, + wallet.GetWalletName(), + walletBalance, + wallet.GetWalletName(), + ), + )) + }) + + // 银行定期取款 + engine.OnPrefix("银行定期取款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + params := strings.Fields(strings.TrimSpace(ctx.State["args"].(string))) + if len(params) < 2 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请输入取款金额和定期存款序号,例如:\n银行定期取款 全部 1\n银行定期取款 100 1(取出第1笔定期存款的部分金额)")) + return + } + + amountStr := params[0] + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + + // 解析定期存款序号 + index, err := strconv.Atoi(params[1]) + if err != nil || index < 1 || index > len(account.FixedDeposits) { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无效的定期存款序号")) + return + } + index-- // 转换为0-based索引 + + fixedDeposit := &account.FixedDeposits[index] + now := time.Now() + isMature := now.After(fixedDeposit.MaturityDate) || now.Equal(fixedDeposit.MaturityDate) + + var totalAmount int + var amount int + + // 处理全部取出的情况 + if amountStr == "全部" { + if isMature { + // 到期取款,计算利息 + interest := int(float64(fixedDeposit.Amount) * fixedDeposit.Rate) + totalAmount = fixedDeposit.Amount + interest + } else { + // 提前取款,扣除手续费(损失50%本金) + penalty := fixedDeposit.Amount / 2 + totalAmount = fixedDeposit.Amount - penalty + ctx.SendChain(message.Text("提示:定期存款未到期提前取出,将扣除50%本金作为手续费")) + } + } else { + // 处理部分取出的情况 + amount, err = strconv.Atoi(amountStr) + if err != nil || amount <= 0 || amount > fixedDeposit.Amount { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("输入的金额无效,请输入有效的正整数")) + return + } + + if isMature { + // 到期部分取款,计算对应利息 + interest := int(float64(amount) * fixedDeposit.Rate) + totalAmount = amount + interest + // 更新定期存款金额 + fixedDeposit.Amount -= amount + } else { + // 提前部分取款,扣除手续费(损失50%本金) + penalty := amount / 2 + totalAmount = amount - penalty + // 更新定期存款金额 + fixedDeposit.Amount -= amount + ctx.SendChain(message.Text("提示:定期存款未到期提前取出,将扣除50%本金作为手续费")) + } + } + + // 如果是全部取出,则移除该定期存款;否则只更新金额 + if amountStr == "全部" { + account.FixedDeposits = append(account.FixedDeposits[:index], account.FixedDeposits[index+1:]...) + } + + account.LastUpdate = now + if err := SaveAccount(account); err != nil { + fmt.Printf("创建新账户保存失败: %v", err) + return + } + + // 增加到钱包 + err = wallet.InsertWalletOf(uid, totalAmount) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("取款失败:", err)) + return + } + + if isMature { + // 使用if-else替代三元运算符 + var principal, interest int + if amountStr == "全部" { + principal = fixedDeposit.Amount + } else { + principal = amount + } + interest = totalAmount - principal + + replyText := fmt.Sprintf( + "定期存款到期取款成功!\n本金:%d%s\n利息:%d%s\n总计:%d%s", + principal, wallet.GetWalletName(), + interest, wallet.GetWalletName(), + totalAmount, wallet.GetWalletName(), + ) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(replyText)) + } else { + // 使用if-else替代三元运算符 + var principal, penalty int + if amountStr == "全部" { + principal = fixedDeposit.Amount + } else { + principal = amount + } + penalty = principal - totalAmount + + replyText := fmt.Sprintf( + "定期存款提前取款成功!\n本金:%d%s\n扣除手续费:%d%s\n实际到账:%d%s", + principal, wallet.GetWalletName(), + penalty, wallet.GetWalletName(), + totalAmount, wallet.GetWalletName(), + ) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(replyText)) + } + }) + + // 银行贷款命令处理(限制贷款天数最多10天) + engine.OnPrefix("银行贷款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + params := strings.Fields(strings.TrimSpace(ctx.State["args"].(string))) + if len(params) < 2 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("格式错误!示例:银行贷款 1000 7(贷款1000,期限7天,最多10天)")) + return + } + + amount, err := strconv.ParseFloat(params[0], 64) + term, errTerm := strconv.Atoi(params[1]) + // 新增:限制期限必须为1-10天 + if err != nil || errTerm != nil || amount <= 0 || term <= 0 || term > 10 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("金额或期限无效!请输入正整数,且期限需在1-10天以内")) + return + } + + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + + if HasActiveLoan(account) { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你有未还清的贷款,无法再次贷款")) + return + } + + // 获取当前钱包余额 + walletBalance := wallet.GetWalletOf(uid) + + // 动态计算最大可贷金额(保持原有逻辑) + var maxLoan int + var limitReason string + if walletBalance < BaseMaxLoanAmount { + maxLoan = BaseMaxLoanAmount + limitReason = fmt.Sprintf("你的钱包余额(%d%s)低于基础贷款额度。", + walletBalance, wallet.GetWalletName()) + } else { + maxLoan = walletBalance * 10 + limitReason = fmt.Sprintf("你的钱包余额(%d%s)充足,可贷余额的10倍", + walletBalance, wallet.GetWalletName()) + } + + // 检查贷款金额是否超出上限 + if int(amount) > maxLoan { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text( + fmt.Sprintf("贷款金额超出上限!%s,当前可贷上限:%d%s", + limitReason, + maxLoan, wallet.GetWalletName(), + ), + )) + return + } + + // 计算利率(保留重生buff对利率的影响) + stacks := getRebirthStacks(account) + actualRate := float64(LoanDailyRate) + if stacks > 0 { + actualRate *= (1 + LoanRateIncreasePercent*float64(stacks)) + } + + // 创建贷款记录 + now := time.Now() + loan := Loan{ + Amount: amount, + Rate: actualRate, + TermDays: term, + StartDate: now, + RepaidAmount: 0, + IsOverdue: false, + } + account.Loans = append(account.Loans, loan) + account.LastUpdate = now + _ = SaveAccount(account) + + // 发放贷款到钱包 + _ = wallet.InsertWalletOf(uid, int(amount)) + + // 计算到期应还总额 + totalRepay := calculateLoanRepay(amount, actualRate, term) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text( + fmt.Sprintf("贷款成功!\n"+ + "金额:%.2f%s\n"+ + "期限:%d天(最长支持10天)\n"+ // 提示用户期限限制 + "日利率:%.2f%%%s\n"+ + "到期应还总额:%.2f%s\n"+ + "到期日:%s", + amount, wallet.GetWalletName(), + term, + actualRate, + func() string { + if stacks > 0 { + return fmt.Sprintf("(基础利率%.2f%% + 重生buff加成%.2f%%)", + float64(LoanDailyRate), + (actualRate-float64(LoanDailyRate)), + ) + } + return "" + }(), + totalRepay, wallet.GetWalletName(), + now.AddDate(0, 0, term).Format("2006-01-02"), + ), + )) + }) + + // 银行还款(支持超额还款自动退款) + engine.OnPrefix("银行还款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + param := strings.TrimSpace(ctx.State["args"].(string)) + amount, err := strconv.ParseFloat(param, 64) + if err != nil || amount <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("还款金额无效,请输入正数字(支持小数)!")) + return + } + + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + if len(account.Loans) == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你暂无未还清的贷款!")) + return + } + + loan := &account.Loans[len(account.Loans)-1] + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + remaining := totalRepay - loan.RepaidAmount + + if remaining <= 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("该笔贷款已还清,无需重复还款!")) + return + } + + walletBalance := float64(wallet.GetWalletOf(uid)) + if walletBalance < amount { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("钱包余额不足,无法还款!")) + return + } + + actualDeduct := amount + if actualDeduct > remaining { + actualDeduct = remaining + } + + err = wallet.InsertWalletOf(uid, -int(math.Round(actualDeduct))) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("还款失败:", err)) + return + } + + loan.RepaidAmount += actualDeduct + account.LastUpdate = time.Now() + if err := SaveAccount(account); err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("还款记录保存失败:", err)) + return + } + + if amount > remaining { + refund := amount - remaining + err = wallet.InsertWalletOf(uid, int(math.Round(refund))) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("还款成功,但退款时发生错误:", err)) + return + } + + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf( + "还款成功!该笔贷款已还清 ✅\n你实际支付了 %.2f%s,应还 %.2f%s,\n多付的 %.2f%s 已退还到你的钱包", + amount, wallet.GetWalletName(), remaining, wallet.GetWalletName(), + refund, wallet.GetWalletName(), + ))) + } else { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf( + "还款成功!\n已还 %.2f%s,剩余需还 %.2f%s", + actualDeduct, wallet.GetWalletName(), + totalRepay - loan.RepaidAmount, wallet.GetWalletName(), + ))) + } + }) + + // 查看我的存款(整合活期和定期存款) + engine.OnPrefix("查看我的存款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + + var replyBuilder strings.Builder + replyBuilder.WriteString("📊 你的存款信息如下:\n\n") + replyBuilder.WriteString(fmt.Sprintf("💴 活期存款:%d%s\n\n", account.CurrentBalance, wallet.GetWalletName())) + replyBuilder.WriteString("⏳ 定期存款:") + + if len(account.FixedDeposits) == 0 { + replyBuilder.WriteString("暂无定期存款") + } else { + for i, deposit := range account.FixedDeposits { + now := time.Now() + isMature := now.After(deposit.MaturityDate) || now.Equal(deposit.MaturityDate) + status := "未到期" + if isMature { + status = "已到期" + } + + daysLeft := "" + if !isMature { + days := int(deposit.MaturityDate.Sub(now).Hours() / 24) + daysLeft = fmt.Sprintf(",剩余%d天到期", days) + } + + interest := int(float64(deposit.Amount) * deposit.Rate) + total := deposit.Amount + interest + + replyBuilder.WriteString(fmt.Sprintf( + " \n%d.金额:%d%s\n期限:%d天\n状态:%s%s\n", + i+1, + deposit.Amount, wallet.GetWalletName(), + deposit.TermDays, + status, + daysLeft, + )) + replyBuilder.WriteString(fmt.Sprintf( + "到期可获利息:%d%s\n到期本息总额:%d%s", + interest, wallet.GetWalletName(), + total, wallet.GetWalletName(), + )) + } + } + + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(replyBuilder.String())) + }) + + // 查看我的贷款(只显示未还清的贷款) + engine.OnFullMatch("查看我的贷款").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + if len(account.Loans) == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你暂无未还清的贷款!")) + return + } + + var activeLoans []Loan + for _, loan := range account.Loans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + if totalRepay - float64(loan.RepaidAmount) > 0 { + activeLoans = append(activeLoans, loan) + } + } + + if len(activeLoans) == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你暂无未还清的贷款!")) + return + } + + reply := message.Message{message.Reply(ctx.Event.MessageID), message.Text("你的未还清贷款信息:\n")} + for _, loan := range activeLoans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + interest := totalRepay - loan.Amount + status := "正常" + if loan.IsOverdue { + status = "逾期 ❗" + } + maturityDateStr := loan.StartDate.AddDate(0, 0, loan.TermDays).Format("2006-01-02") + reply = append(reply, message.Text(fmt.Sprintf( + "金额:%.2f%s\n利息:%.2f%s\n期限:%d天\n到期日:%s\n已还:%.2f%s\n剩余:%.2f%s\n状态:%s", + loan.Amount, wallet.GetWalletName(), + interest, wallet.GetWalletName(), + loan.TermDays, + maturityDateStr, + loan.RepaidAmount, wallet.GetWalletName(), + totalRepay-float64(loan.RepaidAmount), wallet.GetWalletName(), + status, + ))) + } + ctx.Send(reply) + }) + + // 查看今日利率 + engine.OnFullMatch("查看今日利率").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + checkAndUpdateInterest() + + reply := message.Message{message.Reply(ctx.Event.MessageID)} + reply = append(reply, message.Text(fmt.Sprintf("今日活期存款利率:%.2f%%\n\n", dailyInterest.CurrentRate*100))) + reply = append(reply, message.Text("定期存款利率:")) + + var terms []int + for term := range fixedDepositRates { + terms = append(terms, term) + } + sort.Ints(terms) + + for _, term := range terms { + rate := fixedDepositRates[term] + reply = append(reply, message.Text(fmt.Sprintf("\n%d天:%.2f%%", term, rate*100))) + } + reply = append(reply, message.Text(fmt.Sprintf("\n\n贷款日利率:%.2f%%", float64(LoanDailyRate)))) + + ctx.Send(reply) + }) + + // 信仰之跃功能(根据重生次数调整文本) + engine.OnPrefix("我要信仰之跃").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + account := GetOrCreateAccount(uid) + + // 清理过期buff + cleanupExpiredBuffs(account) + + // 检查当前重生buff层数 + currentStacks := getRebirthStacks(account) + if currentStacks >= MaxRebirthStack { + // 获取最早过期buff的剩余时间 + remainingTime, hasBuff := getEarliestRebirthBuffExpiry(account) + + timeInfo := "当前无有效重生buff" + if hasBuff { + if remainingTime <= 0 { + timeInfo = "最早的重生buff已过期,即将自动清除" + } else { + timeInfo = fmt.Sprintf("最早的重生buff将在 %s 后过期,届时可再次进行信仰之跃", formatDuration(remainingTime)) + } + } + + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text( + fmt.Sprintf("你的重生buff已达到最大层数%d层,无法继续进行信仰之跃!\n%s", + MaxRebirthStack, timeInfo), + )) + return + } + + // 检查是否符合无力偿还贷款的条件 + if !hasUnpayableLoan(account) { + walletBalance := wallet.GetWalletOf(account.UserID) + hasActiveDeposit := account.CurrentBalance > 0 + for _, fd := range account.FixedDeposits { + if fd.Amount > 0 { + hasActiveDeposit = true + break + } + } + + hasUnpaidLoan := false + for _, loan := range account.Loans { + totalRepay := calculateLoanRepay(loan.Amount, loan.Rate, loan.TermDays) + if totalRepay - float64(loan.RepaidAmount) > 0 { + hasUnpaidLoan = true + break + } + } + + reason := "当前未满足:" + if walletBalance != 0 { + reason += fmt.Sprintf("钱包余额不为零(当前: %d%s);", walletBalance, wallet.GetWalletName()) + } + if hasActiveDeposit { + reason += "银行存款(活期+定期)不为零;" + } + if !hasUnpaidLoan { + reason += "没有未还清的贷款" + } + + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你不符合信仰之跃的条件,需同时满足:\n1. 钱包余额为零\n2. 银行存款(活期+定期)为零\n3. 存在未还清的贷款\n"+reason)) + return + } + + // 执行重生操作 + applyRebirth(account) + + // 添加重生buff + addRebirthBuff(account) + + // 保存账户变更 + account.LastUpdate = time.Now() + if err := SaveAccount(account); err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("信仰之跃失败,请稍后重试:"+err.Error())) + return + } + + // 获取更新后的层数(新buff已添加,所以是当前实际层数) + newStacks := getRebirthStacks(account) + + // 根据重生层数准备对应文本 + var text1, text2 string + switch newStacks { + case 1: + // 第一次重生(层数为1) + text1 = "上一世,你失败了,这一世,你要拿回属于你的一切.jpg" + text2 = "但你似乎也发现了,银行对你带有些许的恶意" + case 2: + // 第二次重生(层数为2) + text1 = "上一世...咦,你似乎发觉自己好像说过这句话了,好奇怪啊" + text2 = "银行的恶意变深了...?你突然发觉自己似乎重生了不止一次" + case 3: + // 第三次重生(层数为3) + text1 = "上...不对,这是我第几次重生了?" + text2 = "银行的恶意达到了顶峰,这次重生,似乎已经抵达了某种上限。" + // default: + // // 超过3层时的默认文本(应对可能的扩展) + // text1 = "轮回往复,你已经记不清这是第几次重生了" + // text2 = "银行的恶意达到了顶峰,你感觉自己快要触碰到世界的真相..." + } + + // 处理延迟消息 + msgID, ok := ctx.Event.MessageID.(int64) + if !ok { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("消息ID解析失败")) + return + } + go func(ctx *zero.Ctx, msgID int64) { + ctx.SendChain(message.Reply(msgID), message.Text("正在为你生成场景天台...生成完毕。你一跃而下,成功完成了信仰之跃!")) + time.Sleep(time.Second * 2) + + ctx.SendChain(message.Reply(msgID), message.Text(fmt.Sprintf( + "你所有贷款已清零\n你获得了「重生」buff\n当前重生buff: %d/%d层(每层7天后自动消除)", + newStacks, MaxRebirthStack, + ))) + time.Sleep(time.Second * 2) + + ctx.SendChain(message.Reply(msgID), message.Text(text1)) + time.Sleep(time.Second * 2) + + ctx.SendChain(message.Reply(msgID), message.Text(text2)) + }(ctx, msgID) + }) +} \ No newline at end of file diff --git a/plugin/bank/model.go b/plugin/bank/model.go new file mode 100644 index 0000000000..aff43076ad --- /dev/null +++ b/plugin/bank/model.go @@ -0,0 +1,46 @@ +// Package bank 银行 +package bank + +import "time" + +// Buff 给Buff添加相关参数 +type Buff struct { + Name string `yaml:"name"` // buff名称 + ExpireTime time.Time `yaml:"expire_time"` // 过期时间 +} + +// FixedDeposit 定期存款信息 +type FixedDeposit struct { + Amount int `yaml:"amount"` // 存款金额 + TermDays int `yaml:"term_days"` // 存款期限(天) + Rate float64 `yaml:"rate"` // 存款利率 + StartDate time.Time `yaml:"start_date"` // 开始日期 + MaturityDate time.Time `yaml:"maturity_date"` // 到期日期 +} + +// Loan 贷款信息 +type Loan struct { + Amount float64 `yaml:"amount"` // 贷款金额 + Rate float64 `yaml:"rate"` // 贷款日利率 + TermDays int `yaml:"term_days"` // 贷款期限(天) + StartDate time.Time `yaml:"start_date"` // 贷款发放日期 + RepaidAmount float64 `yaml:"repaid_amount"` // 已还金额 + IsOverdue bool `yaml:"is_overdue"` // 是否逾期 +} + +// Account 银行账户信息 +type Account struct { + UserID int64 `yaml:"user_id"` // 用户ID + CurrentBalance int `yaml:"current_balance"` // 活期余额 + FixedDeposits []FixedDeposit `yaml:"fixed_deposits"` // 定期存款列表 + Loans []Loan `yaml:"loans"` // 贷款列表 + LastUpdate time.Time `yaml:"last_update"` // 最后更新时间 + Buffs []Buff `yaml:"buffs"` // 拥有的buff +} + +// InterestInfo 利息信息 +type InterestInfo struct { + CurrentRate float64 `yaml:"current_rate"` // 今日活期利率 + LastDate string `yaml:"last_date"` // 最后更新日期 +} + diff --git a/plugin/wallet/wallet.go b/plugin/wallet/wallet.go index b44abd9ac3..c42923f68d 100644 --- a/plugin/wallet/wallet.go +++ b/plugin/wallet/wallet.go @@ -10,6 +10,7 @@ import ( "time" "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/ZeroBot-Plugin/plugin/bank" "github.com/FloatTech/floatbox/binary" "github.com/FloatTech/floatbox/file" ctrl "github.com/FloatTech/zbpctrl" @@ -20,6 +21,7 @@ import ( "github.com/wcharczuk/go-chart/v2" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" + ) func init() { @@ -235,6 +237,13 @@ func init() { return } + // 检查用户是否有未还清且未逾期的贷款 + account := bank.GetOrCreateAccount(ctx.Event.UserID) + if bank.HasActiveLoan(account) { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你有未还清且未逾期的贷款,期间禁止转账操作")) + return + } + // 开始转账流程 if amount > wallet.GetWalletOf(ctx.Event.UserID) { ctx.SendChain(message.Text("[ERROR]:钱包余额不足,转账失败"))