diff --git a/app/Http/Controllers/ChatController.php b/app/Http/Controllers/ChatController.php
index d0f3cee..513db70 100644
--- a/app/Http/Controllers/ChatController.php
+++ b/app/Http/Controllers/ChatController.php
@@ -149,17 +149,29 @@ class ChatController extends Controller
return response()->json(['status' => 'error'], 401);
}
- // 1. 心跳经验:通过 Redis 限制最小间隔(默认30秒),防止频繁点击刷经验
- $expCooldownKey = "heartbeat_exp:{$user->id}";
- $canGainExp = ! Redis::exists($expCooldownKey);
+ // 1. 心跳奖励:通过 Redis 限制最小间隔(默认30秒),防止频繁点击
+ $cooldownKey = "heartbeat_exp:{$user->id}";
+ $canGainReward = ! Redis::exists($cooldownKey);
+ $actualExpGain = 0;
+ $actualJjbGain = 0;
- if ($canGainExp) {
- $expGain = (int) Sysparam::getValue('exp_per_heartbeat', '1');
+ if ($canGainReward) {
+ // 经验奖励(支持固定值 "1" 或范围 "1-10")
+ $expGain = $this->parseRewardValue(Sysparam::getValue('exp_per_heartbeat', '1'));
$expMultiplier = $this->vipService->getExpMultiplier($user);
- $user->exp_num += (int) round($expGain * $expMultiplier);
+ $actualExpGain = (int) round($expGain * $expMultiplier);
+ $user->exp_num += $actualExpGain;
- // 设置冷却(30秒内不再给经验)
- Redis::setex($expCooldownKey, 30, 1);
+ // 金币奖励(支持固定值 "1" 或范围 "1-5")
+ $jjbGain = $this->parseRewardValue(Sysparam::getValue('jjb_per_heartbeat', '0'));
+ if ($jjbGain > 0) {
+ $jjbMultiplier = $this->vipService->getJjbMultiplier($user);
+ $actualJjbGain = (int) round($jjbGain * $jjbMultiplier);
+ $user->jjb = ($user->jjb ?? 0) + $actualJjbGain;
+ }
+
+ // 设置冷却(30秒内不再给奖励)
+ Redis::setex($cooldownKey, 30, 1);
}
// 2. 使用 sysparam 表中可配置的等级-经验阈值计算等级
@@ -263,6 +275,9 @@ class ChatController extends Controller
'status' => 'success',
'data' => [
'exp_num' => $user->exp_num,
+ 'jjb' => $user->jjb ?? 0,
+ 'exp_gain' => $actualExpGain,
+ 'jjb_gain' => $actualJjbGain,
'user_level' => $user->user_level,
'leveled_up' => $leveledUp,
'is_max_level' => $user->user_level >= $superLevel,
@@ -408,4 +423,31 @@ class ChatController extends Controller
'announcement' => $room->announcement,
]);
}
+
+ /**
+ * 解析奖励数值配置(支持固定值或范围格式)
+ *
+ * 支持格式:
+ * "5" → 固定返回 5
+ * "1-10" → 随机返回 1~10 之间的整数
+ * "0" → 返回 0(关闭该奖励)
+ *
+ * @param string $value 配置值
+ * @return int 解析后的奖励数值
+ */
+ private function parseRewardValue(string $value): int
+ {
+ $value = trim($value);
+
+ // 支持范围格式 "min-max"
+ if (str_contains($value, '-')) {
+ $parts = explode('-', $value, 2);
+ $min = max(0, (int) $parts[0]);
+ $max = max($min, (int) $parts[1]);
+
+ return rand($min, $max);
+ }
+
+ return max(0, (int) $value);
+ }
}
diff --git a/database/migrations/2026_02_27_004100_seed_jjb_per_heartbeat_sysparam.php b/database/migrations/2026_02_27_004100_seed_jjb_per_heartbeat_sysparam.php
new file mode 100644
index 0000000..1ce1593
--- /dev/null
+++ b/database/migrations/2026_02_27_004100_seed_jjb_per_heartbeat_sysparam.php
@@ -0,0 +1,50 @@
+where('alias', 'jjb_per_heartbeat')->exists()) {
+ DB::table('sysparam')->insert([
+ 'alias' => 'jjb_per_heartbeat',
+ 'body' => '1-3',
+ 'guidetxt' => '💰 每次心跳金币奖励(支持固定值如"1",或范围如"1-5";设为0关闭)',
+ ]);
+ }
+
+ // 更新经验配置描述(说明支持范围格式)
+ DB::table('sysparam')
+ ->where('alias', 'exp_per_heartbeat')
+ ->update(['guidetxt' => '⚡ 每次心跳经验奖励(支持固定值如"1",或范围如"1-10";设为0关闭)']);
+ }
+
+ /**
+ * 回滚:删除金币配置记录
+ */
+ public function down(): void
+ {
+ DB::table('sysparam')->where('alias', 'jjb_per_heartbeat')->delete();
+
+ DB::table('sysparam')
+ ->where('alias', 'exp_per_heartbeat')
+ ->update(['guidetxt' => '每次心跳经验值']);
+ }
+};
diff --git a/resources/views/chat/partials/scripts.blade.php b/resources/views/chat/partials/scripts.blade.php
index e2bc279..b058257 100644
--- a/resources/views/chat/partials/scripts.blade.php
+++ b/resources/views/chat/partials/scripts.blade.php
@@ -830,11 +830,18 @@
let levelInfo = '';
if (d.is_max_level) {
- levelInfo = `级别(${d.user_level});累积经验(${d.exp_num});已满级。`;
+ levelInfo = `级别(${d.user_level});经验(${d.exp_num});金币(${d.jjb}枚);已满级。`;
} else {
- const requiredExp = d.user_level * d.user_level * 10;
- const remaining = Math.max(0, requiredExp - d.exp_num);
- levelInfo = `级别(${d.user_level});累积经验(${d.exp_num});还有(${remaining})升级。`;
+ levelInfo = `级别(${d.user_level});经验(${d.exp_num});金币(${d.jjb}枚)。`;
+ }
+
+ // 本次获得的奖励提示
+ let gainInfo = '';
+ if (d.exp_gain > 0 || d.jjb_gain > 0) {
+ const parts = [];
+ if (d.exp_gain > 0) parts.push(`经验+${d.exp_gain}`);
+ if (d.jjb_gain > 0) parts.push(`金币+${d.jjb_gain}`);
+ gainInfo = `(本次: ${parts.join(', ')})`;
}
if (data.data.leveled_up) {
@@ -850,7 +857,7 @@
const detailDiv = document.createElement('div');
detailDiv.className = 'msg-line';
detailDiv.innerHTML =
- `【${levelTitle}存点】您的最新情况:${levelInfo}(${timeStr})`;
+ `【${levelTitle}存点】您的最新情况:${levelInfo} ${gainInfo}(${timeStr})`;
container2.appendChild(detailDiv);
if (autoScroll) container2.scrollTop = container2.scrollHeight;
} else {