功能:职务奖励金币发放系统
数据库: - positions 新增 daily_reward_limit(单日累计上限) - positions 新增 recipient_daily_limit(同一接收者每日次数上限) 后端: - CurrencySource::POSITION_REWARD 新枚举值 - AdminCommandController::reward() 三层限额校验 ① 单次上限 ② 单日累计上限 ③ 同一接收者每日次数 写履职记录(PositionAuthorityLog)+ UserCurrencyService 聊天室悄悄话通知接收者 - POST /command/reward 路由注册 前端(user-actions.blade.php): - 名片按钮行 2+1 布局(加好友/送礼物/送金币) - 送金币仅在 myMaxReward>0 时显示(职务持有者) - 内联奖励金币面板:金额输入 + 确认发放 + 说明文字 - sendReward() 前端校验 + API 调用 + chatDialog 反馈 后台(positions/index): - 编辑表单新增两个奖励限额字段 - PositionController 验证规则同步更新
This commit is contained in:
@@ -93,6 +93,11 @@
|
||||
giftCount: 1,
|
||||
sendingGift: false,
|
||||
|
||||
// 职务奖励金币
|
||||
rewardAmount: 0,
|
||||
sendingReward: false,
|
||||
showRewardPanel: false,
|
||||
|
||||
// 任命相关
|
||||
showAppointPanel: false,
|
||||
appointPositions: [],
|
||||
@@ -447,17 +452,56 @@
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
alert(data.message);
|
||||
this.$alert(data.message, data.status === 'success' ? '送礼成功 🎁' : '操作失败',
|
||||
data.status === 'success' ? '#e11d48' : '#cc4444');
|
||||
if (data.status === 'success') {
|
||||
this.showUserModal = false;
|
||||
this.giftCount = 1;
|
||||
}
|
||||
} catch (e) {
|
||||
alert('网络异常');
|
||||
this.$alert('网络异常', '错误', '#cc4444');
|
||||
}
|
||||
this.sendingGift = false;
|
||||
},
|
||||
|
||||
/** 职务奖励:向用户发放金币(凭空产生,记入履职记录) */
|
||||
async sendReward() {
|
||||
if (this.sendingReward) return;
|
||||
const maxOnce = window.chatContext?.myMaxReward ?? 0;
|
||||
const amount = parseInt(this.rewardAmount, 10);
|
||||
if (!amount || amount <= 0) {
|
||||
this.$alert('请输入有效的奖励金额', '提示', '#f59e0b');
|
||||
return;
|
||||
}
|
||||
if (amount > maxOnce) {
|
||||
this.$alert(`单次奖励上限为 ${maxOnce} 金币`, '超出上限', '#cc4444');
|
||||
return;
|
||||
}
|
||||
this.sendingReward = true;
|
||||
try {
|
||||
const res = await fetch(window.chatContext.rewardUrl, {
|
||||
method: 'POST',
|
||||
headers: this._headers(),
|
||||
body: JSON.stringify({
|
||||
username: this.userInfo.username,
|
||||
room_id: window.chatContext.roomId,
|
||||
amount,
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
const ok = data.status === 'success';
|
||||
this.$alert(data.message, ok ? '奖励发放成功 🎉' : '操作失败',
|
||||
ok ? '#d97706' : '#cc4444');
|
||||
if (ok) {
|
||||
this.showRewardPanel = false;
|
||||
this.rewardAmount = 0;
|
||||
}
|
||||
} catch (e) {
|
||||
this.$alert('网络异常,请稍后重试', '错误', '#cc4444');
|
||||
}
|
||||
this.sendingReward = false;
|
||||
},
|
||||
|
||||
/** 通用请求头 */
|
||||
_headers() {
|
||||
return {
|
||||
@@ -610,23 +654,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 普通操作按鈕:写私信 + 送花 + 内联礼物面板 --}}
|
||||
<div x-data="{ showGiftPanel: false }" x-show="userInfo.username !== window.chatContext.username">
|
||||
{{-- 操作按钮区:加好友 + 送礼物 + 送金币(有职务且有奖励权限时显示) --}}
|
||||
<div x-data="{ showGiftPanel: false, showRewardPanel: false }" x-show="userInfo.username !== window.chatContext.username">
|
||||
|
||||
<div class="modal-actions" style="margin-bottom: 0;">
|
||||
{{-- 加好友 / 删好友(替代写私信) --}}
|
||||
<div class="modal-actions" style="margin-bottom: 0; display: flex; gap: 6px; flex-wrap: wrap;">
|
||||
{{-- 加好友 / 删好友 --}}
|
||||
<button x-on:click="toggleFriend()" :disabled="friendLoading"
|
||||
:style="is_friend
|
||||
?
|
||||
'background: #f1f5f9; color: #6b7280; border: 1px solid #d1d5db;' :
|
||||
'background: linear-gradient(135deg,#16a34a,#22c55e); color:#fff; border:none;'"
|
||||
style="padding: 7px 14px; border-radius: 5px; font-size: 12px;
|
||||
style="flex:1; padding: 7px 10px; border-radius: 5px; font-size: 12px;
|
||||
cursor: pointer; font-weight: bold; transition: opacity .15s;"
|
||||
x-text="friendLoading ? '处理中…' : (is_friend ? '✅ 已是好友 (点击删除)' : '➕ 加好友')"></button>
|
||||
{{-- 送花按鈕(与写私信并列) --}}
|
||||
<button class="btn-whisper" x-on:click="showGiftPanel = !showGiftPanel">
|
||||
x-text="friendLoading ? '处理中…' : (is_friend ? '✅ 已是好友' : '➕ 加好友')"></button>
|
||||
|
||||
{{-- 送礼物按钮 --}}
|
||||
<button class="btn-whisper" style="flex:1;"
|
||||
x-on:click="showGiftPanel = !showGiftPanel; showRewardPanel = false;">
|
||||
🎁 送礼物
|
||||
</button>
|
||||
|
||||
{{-- 送金币按钮:仅职务持有者且有 max_reward 时显示 --}}
|
||||
<button x-show="window.chatContext?.myMaxReward > 0"
|
||||
style="flex:1; padding: 7px 10px; border-radius: 5px; font-size: 12px; font-weight: bold; cursor: pointer;
|
||||
background: linear-gradient(135deg,#f59e0b,#d97706); color:#fff; border:none;"
|
||||
x-on:click="showRewardPanel = !showRewardPanel; showGiftPanel = false;">
|
||||
🪙 送金币
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- 内联礼物面板 --}}
|
||||
@@ -679,6 +733,38 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 内联奖励金币面板(仅职务持有者且有 max_reward 时可用) --}}
|
||||
<div x-show="showRewardPanel" x-transition
|
||||
style="display: none; padding: 12px 16px; background: #fffbeb; border-top: 2px solid #f59e0b;">
|
||||
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||
<span style="font-size: 13px; color: #92400e; font-weight: bold;">🪙 发放奖励金币</span>
|
||||
<span style="font-size: 11px; color: #b45309;">
|
||||
单次上限:<b x-text="window.chatContext?.myMaxReward ?? 0"></b> 金币
|
||||
</span>
|
||||
<button x-on:click="showRewardPanel = false"
|
||||
style="background: none; border: none; color: #94a3b8; cursor: pointer; font-size: 18px; line-height: 1;">×</button>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 8px; align-items: center;">
|
||||
<input type="number" x-model.number="rewardAmount" :min="1"
|
||||
:max="window.chatContext?.myMaxReward ?? 9999" placeholder="输入金额"
|
||||
style="flex:1; height: 36px; padding: 0 10px; border: 1px solid #fcd34d;
|
||||
border-radius: 6px; font-size: 14px; color: #92400e; background: #fff;
|
||||
outline: none; box-sizing: border-box;">
|
||||
<button x-on:click="sendReward()" :disabled="sendingReward || !rewardAmount"
|
||||
style="height: 36px; padding: 0 18px; background: linear-gradient(135deg,#f59e0b,#d97706);
|
||||
color:#fff; border:none; border-radius: 6px; font-size: 13px; font-weight: bold; cursor: pointer; white-space: nowrap;"
|
||||
:style="sendingReward || !rewardAmount ? 'opacity:0.6; cursor:not-allowed;' : ''">
|
||||
<span x-text="sendingReward ? '发放中...' : '🎉 确认发放'"></span>
|
||||
</button>
|
||||
</div>
|
||||
<p style="margin: 6px 0 0; font-size: 10px; color: #b45309; opacity: 0.8;">
|
||||
金币将直接发放给对方账户,本操作记入你的履职记录。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 管理操作 + 职务操作 合并折叠区 --}}
|
||||
|
||||
Reference in New Issue
Block a user