优化:奖励弹窗加宽+4列额度+最近10条记录+确认按钮醒目
- 弹窗宽度 320→520px(max-width:95vw 自适应) - 额度四格改为一行4列(单次上限/单日上限/今日已发/剩余额度) - 确认按钮改为橙红渐变+投影,视觉更突出 - 输入框下方显示最近10条发放记录(目标/金额/时间) - 发放成功后实时在历史列表头部插入新纪录 - rewardQuota 接口统一返回 recent_rewards(最近10条)
This commit is contained in:
@@ -581,12 +581,29 @@ class AdminCommandController extends Controller
|
||||
$admin = Auth::user();
|
||||
$isSuperAdmin = $admin->id === 1;
|
||||
|
||||
// 最近 10 条本人发放记录(含目标用户名)
|
||||
$recent = PositionAuthorityLog::with('targetUser:id,username')
|
||||
->where('user_id', $admin->id)
|
||||
->where('action_type', 'reward')
|
||||
->latest()
|
||||
->limit(10)
|
||||
->get()
|
||||
->map(fn ($log) => [
|
||||
'target' => $log->targetUser?->username ?? '未知',
|
||||
'amount' => $log->amount,
|
||||
'created_at' => $log->created_at?->format('m-d H:i'),
|
||||
]);
|
||||
|
||||
if ($isSuperAdmin) {
|
||||
return response()->json([
|
||||
'max_once' => null,
|
||||
'daily_limit' => null,
|
||||
'today_sent' => 0,
|
||||
'today_sent' => (int) PositionAuthorityLog::where('user_id', $admin->id)
|
||||
->where('action_type', 'reward')
|
||||
->whereDate('created_at', today())
|
||||
->sum('amount'),
|
||||
'daily_remaining' => null,
|
||||
'recent_rewards' => $recent,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -597,11 +614,12 @@ class AdminCommandController extends Controller
|
||||
'daily_limit' => null,
|
||||
'today_sent' => 0,
|
||||
'daily_remaining' => null,
|
||||
'recent_rewards' => $recent,
|
||||
]);
|
||||
}
|
||||
|
||||
// 今日已发放总额(以 user_id 统计操作人自己的发放)
|
||||
$todaySent = PositionAuthorityLog::where('user_id', $admin->id)
|
||||
// 今日已发放总额
|
||||
$todaySent = (int) PositionAuthorityLog::where('user_id', $admin->id)
|
||||
->where('action_type', 'reward')
|
||||
->whereDate('created_at', today())
|
||||
->sum('amount');
|
||||
@@ -610,10 +628,11 @@ class AdminCommandController extends Controller
|
||||
$remaining = $dailyLimit !== null ? max(0, $dailyLimit - $todaySent) : null;
|
||||
|
||||
return response()->json([
|
||||
'max_once' => $position->max_reward, // null = 不限, 0 = 禁止, N = 有上限
|
||||
'daily_limit' => $dailyLimit, // null = 不限
|
||||
'today_sent' => (int) $todaySent,
|
||||
'daily_remaining' => $remaining, // null = 不限
|
||||
'max_once' => $position->max_reward,
|
||||
'daily_limit' => $dailyLimit,
|
||||
'today_sent' => $todaySent,
|
||||
'daily_remaining' => $remaining,
|
||||
'recent_rewards' => $recent,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -884,7 +884,7 @@
|
||||
amount: '',
|
||||
sending: false,
|
||||
loading: false,
|
||||
quota: { max_once: null, daily_limit: null, today_sent: 0, daily_remaining: null },
|
||||
quota: { max_once: null, daily_limit: null, today_sent: 0, daily_remaining: null, recent_rewards: [] },
|
||||
|
||||
fmt(v) {
|
||||
if (v === null) return '不限';
|
||||
@@ -903,7 +903,8 @@
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
this.quota = await res.json();
|
||||
} catch { this.quota = { max_once: null, daily_limit: null, today_sent: 0, daily_remaining: null }; }
|
||||
if (!this.quota.recent_rewards) this.quota.recent_rewards = [];
|
||||
} catch { this.quota = { max_once: null, daily_limit: null, today_sent: 0, daily_remaining: null, recent_rewards: [] }; }
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
@@ -912,7 +913,7 @@
|
||||
const amt = parseInt(this.amount, 10);
|
||||
if (!amt || amt <= 0) { alert('请输入有效金额'); return; }
|
||||
const maxOnce = window.chatContext?.myMaxReward;
|
||||
if (maxOnce === 0) { alert('你的职务没有奖励发放权限'); return; }
|
||||
if (maxOnce === 0) { alert('你的职务没有奖励发放权限'); return; }
|
||||
if (maxOnce > 0 && amt > maxOnce) { alert('超出单次上限 ' + maxOnce + ' 金币'); return; }
|
||||
this.sending = true;
|
||||
try {
|
||||
@@ -931,6 +932,14 @@
|
||||
if (this.quota.daily_remaining !== null) {
|
||||
this.quota.daily_remaining = Math.max(0, this.quota.daily_remaining - amt);
|
||||
}
|
||||
// 在历史记录头部插入
|
||||
const now = new Date();
|
||||
const mm = String(now.getMonth()+1).padStart(2,'0');
|
||||
const dd = String(now.getDate()).padStart(2,'0');
|
||||
const hh = String(now.getHours()).padStart(2,'0');
|
||||
const mi = String(now.getMinutes()).padStart(2,'0');
|
||||
this.quota.recent_rewards.unshift({ target: this.targetUsername, amount: amt, created_at: mm+'-'+dd+' '+hh+':'+mi });
|
||||
if (this.quota.recent_rewards.length > 10) this.quota.recent_rewards.pop();
|
||||
this.amount = '';
|
||||
alert(data.message);
|
||||
} else {
|
||||
@@ -943,59 +952,85 @@
|
||||
<div x-show="show" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9900;" x-on:click.self="show = false">
|
||||
<div x-show="show"
|
||||
style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
|
||||
width:320px; background:#fff; border-radius:16px;
|
||||
width:520px; max-width:95vw; background:#fff; border-radius:16px;
|
||||
box-shadow:0 20px 60px rgba(0,0,0,.25); overflow:hidden;">
|
||||
<div style="background:linear-gradient(135deg,#f59e0b,#d97706); padding:14px 18px;
|
||||
{{-- 标题栏 --}}
|
||||
<div style="background:linear-gradient(135deg,#f59e0b,#d97706); padding:14px 20px;
|
||||
display:flex; align-items:center; justify-content:space-between;">
|
||||
<div>
|
||||
<div style="color:#fff; font-weight:bold; font-size:15px;">🪙 发放奖励金币</div>
|
||||
<div style="color:rgba(255,255,255,.85); font-size:12px; margin-top:2px;" x-text="'发给:' + targetUsername"></div>
|
||||
<div style="color:#fff; font-weight:bold; font-size:16px;">🪙 发放奖励金币</div>
|
||||
<div style="color:rgba(255,255,255,.9); font-size:12px; margin-top:2px;" x-text="'发给:' + targetUsername"></div>
|
||||
</div>
|
||||
<button x-on:click="show = false"
|
||||
style="background:rgba(255,255,255,.2); border:none; color:#fff; width:28px; height:28px;
|
||||
border-radius:50%; cursor:pointer; font-size:16px; line-height:28px; text-align:center;">×</button>
|
||||
style="background:rgba(255,255,255,.25); border:none; color:#fff; width:30px; height:30px;
|
||||
border-radius:50%; cursor:pointer; font-size:18px; line-height:30px; text-align:center;">×</button>
|
||||
</div>
|
||||
<div style="padding:16px 18px 0;">
|
||||
{{-- 额度四格(一行4列) --}}
|
||||
<div style="padding:16px 20px 0;">
|
||||
<div x-show="loading" style="text-align:center; color:#b45309; font-size:13px; padding:12px 0;">加载额度信息…</div>
|
||||
<div x-show="!loading" style="display:grid; grid-template-columns:1fr 1fr; gap:8px;">
|
||||
<div x-show="!loading" style="display:grid; grid-template-columns:repeat(4,1fr); gap:8px;">
|
||||
<div style="background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px; text-align:center;">
|
||||
<div style="font-size:10px; color:#b45309; margin-bottom:4px;">单次上限</div>
|
||||
<div style="font-size:14px; font-weight:bold; color:#92400e;" x-text="fmt(quota.max_once)"></div>
|
||||
<div style="font-size:13px; font-weight:bold; color:#92400e;" x-text="fmt(quota.max_once)"></div>
|
||||
</div>
|
||||
<div style="background:#fffbeb; border:1px solid #fde68a; border-radius:8px; padding:10px; text-align:center;">
|
||||
<div style="font-size:10px; color:#b45309; margin-bottom:4px;">单日上限</div>
|
||||
<div style="font-size:14px; font-weight:bold; color:#92400e;" x-text="fmt(quota.daily_limit)"></div>
|
||||
<div style="font-size:13px; font-weight:bold; color:#92400e;" x-text="fmt(quota.daily_limit)"></div>
|
||||
</div>
|
||||
<div style="background:#f0fdf4; border:1px solid #bbf7d0; border-radius:8px; padding:10px; text-align:center;">
|
||||
<div style="font-size:10px; color:#166534; margin-bottom:4px;">今日已发</div>
|
||||
<div style="font-size:14px; font-weight:bold; color:#15803d;" x-text="quota.today_sent.toLocaleString() + ' 金币'"></div>
|
||||
<div style="font-size:13px; font-weight:bold; color:#15803d;" x-text="quota.today_sent.toLocaleString() + ' 金币'"></div>
|
||||
</div>
|
||||
<div style="background:#f0fdf4; border:1px solid #bbf7d0; border-radius:8px; padding:10px; text-align:center;">
|
||||
<div style="font-size:10px; color:#166534; margin-bottom:4px;">剩余额度</div>
|
||||
<div style="font-size:14px; font-weight:bold; color:#15803d;" x-text="fmt(quota.daily_remaining)"></div>
|
||||
<div style="font-size:13px; font-weight:bold; color:#15803d;" x-text="fmt(quota.daily_remaining)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding:16px 18px 18px;">
|
||||
<div style="display:flex; gap:8px; align-items:center; margin-bottom:10px;">
|
||||
{{-- 输入区 --}}
|
||||
<div style="padding:14px 20px 0;">
|
||||
<div style="display:flex; gap:8px; align-items:center;">
|
||||
<input type="number" x-model.number="amount"
|
||||
:placeholder="quota.max_once ? '最多 ' + quota.max_once + ' 金币' : '请输入金额'"
|
||||
:placeholder="quota.max_once ? '最多 ' + quota.max_once + ' 金币' : '请输入发放金额'"
|
||||
:max="quota.max_once || 999999" min="1"
|
||||
x-on:keydown.enter="send()"
|
||||
style="flex:1; height:40px; padding:0 12px; border:2px solid #fcd34d;
|
||||
border-radius:8px; font-size:14px; color:#92400e; outline:none; box-sizing:border-box;">
|
||||
style="flex:1; height:44px; padding:0 14px; border:2px solid #fcd34d;
|
||||
border-radius:10px; font-size:15px; color:#92400e; outline:none; box-sizing:border-box;">
|
||||
<button x-on:click="send()" :disabled="sending || !amount"
|
||||
style="height:40px; padding:0 16px; background:linear-gradient(135deg,#f59e0b,#d97706);
|
||||
color:#fff; border:none; border-radius:8px; font-size:13px; font-weight:bold;
|
||||
cursor:pointer; white-space:nowrap; min-width:80px;"
|
||||
:style="(sending || !amount) ? 'opacity:.6; cursor:not-allowed;' : ''">
|
||||
<span x-text="sending ? '发放中…' : '🎉 确认'"></span>
|
||||
style="height:44px; padding:0 24px; border:none; border-radius:10px; font-size:14px;
|
||||
font-weight:bold; cursor:pointer; white-space:nowrap;
|
||||
background:linear-gradient(135deg,#ea580c,#dc2626);
|
||||
color:#fff; box-shadow:0 4px 12px rgba(234,88,12,.4);"
|
||||
:style="(sending || !amount) ? 'opacity:.5; cursor:not-allowed; box-shadow:none;' : ''">
|
||||
<span x-text="sending ? '发放中…' : '🎉 确认发放'"></span>
|
||||
</button>
|
||||
</div>
|
||||
<p style="margin:0; font-size:10px; color:#b45309; opacity:.8; text-align:center;">
|
||||
<p style="margin:6px 0 0; font-size:10px; color:#b45309; opacity:.75; text-align:center;">
|
||||
金币凭空产生并直接发放给对方,本操作记入你的履职记录。
|
||||
</p>
|
||||
</div>
|
||||
{{-- 最近 10 条记录 --}}
|
||||
<div style="padding:12px 20px 16px;">
|
||||
<div style="font-size:11px; color:#78716c; font-weight:bold; margin-bottom:6px; border-top:1px solid #f5f5f4; padding-top:10px;">
|
||||
📋 最近发放记录
|
||||
</div>
|
||||
<div x-show="loading" style="font-size:11px; color:#aaa; text-align:center; padding:4px 0;">加载中…</div>
|
||||
<div x-show="!loading && quota.recent_rewards.length === 0"
|
||||
style="font-size:11px; color:#aaa; text-align:center; padding:4px 0;">暂无记录</div>
|
||||
<div x-show="!loading" style="max-height:160px; overflow-y:auto;">
|
||||
<template x-for="(r, i) in quota.recent_rewards" :key="i">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center;
|
||||
font-size:11px; padding:4px 6px; border-radius:4px;"
|
||||
:style="i % 2 === 0 ? 'background:#fafaf9;' : ''">
|
||||
<span style="color:#57534e;">
|
||||
<span style="color:#92400e; font-weight:bold;" x-text="r.target"></span>
|
||||
</span>
|
||||
<span style="color:#059669; font-weight:bold;" x-text="'+' + r.amount.toLocaleString() + ' 金币'"></span>
|
||||
<span style="color:#a8a29e;" x-text="r.created_at"></span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user