// +---------------------------------------------------------------------- declare (strict_types = 1); namespace ywxapp\service; use think\facade\Db; /** * 用户钱包(金币)服务 * 金币用于虚拟礼物、抽奖等趣味互动;余额变动同时写入 user_bill 流水。 */ class WalletService { /** * 确保钱包行存在 */ public static function ensure(int $uid): void { $exist = Db::name('member_wallets')->where('uid', $uid)->value('id'); if (! $exist) { Db::name('member_wallets')->insert([ 'uid' => $uid, 'balance' => 0, 'coins' => 0, 'total_recharge' => 0, 'total_consume' => 0, 'create_at' => time(), 'update_at' => time(), ]); } } /** * 当前金币 */ public static function getCoins(int $uid): int { self::ensure($uid); return (int) Db::name('member_wallets')->where('uid', $uid)->value('coins'); } /** * 增加金币(赠送/中奖/充值),bill type=1 */ public static function incCoins(int $uid, int $num, string $desc = ''): bool { if ($num <= 0) { return true; } self::ensure($uid); Db::startTrans(); try { Db::name('member_wallets')->where('uid', $uid)->inc('coins', $num)->update(['update_at' => time()]); Db::name('member_bill')->insert([ 'uid' => $uid, 'type' => 1, 'amount' => $num, 'currency' => 2, 'status' => 1, 'description' => $desc, 'create_at' => time(), 'update_at' => time(), ]); Db::commit(); return true; } catch (\Throwable $e) { Db::rollback(); throw $e; } } /** * 扣减金币,不足抛异常,bill type=2 */ public static function decCoins(int $uid, int $num, string $desc = ''): bool { if ($num <= 0) { return true; } self::ensure($uid); $cur = Db::name('member_wallets')->where('uid', $uid)->lock(true)->value('coins'); if ($cur < $num) { throw new \Exception('金币不足'); } Db::startTrans(); try { Db::name('member_wallets')->where('uid', $uid) ->dec('coins', $num) ->inc('total_consume', $num) ->update(['update_at' => time()]); Db::name('member_bill')->insert([ 'uid' => $uid, 'type' => 2, 'amount' => $num, 'currency' => 2, 'status' => 1, 'description' => $desc, 'create_at' => time(), 'update_at' => time(), ]); Db::commit(); return true; } catch (\Throwable $e) { Db::rollback(); throw $e; } } }