迁移奖励金币弹窗脚本
This commit is contained in:
@@ -1,4 +1,218 @@
|
||||
// 聊天室职务奖励金币弹窗入口,提供 openRewardModal 全局兼容函数。
|
||||
// 聊天室职务奖励金币弹窗组件,负责额度查询、发放提交和全局打开入口。
|
||||
|
||||
const EMPTY_REWARD_QUOTA = {
|
||||
max_once: null,
|
||||
daily_limit: null,
|
||||
today_sent: 0,
|
||||
daily_remaining: null,
|
||||
recent_rewards: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成新的空额度对象,避免多个弹窗状态共用同一引用。
|
||||
*
|
||||
* @returns {Record<string, any>}
|
||||
*/
|
||||
function emptyRewardQuota() {
|
||||
return {
|
||||
...EMPTY_REWARD_QUOTA,
|
||||
recent_rewards: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 CSRF Token。
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function csrfToken() {
|
||||
return document.querySelector('meta[name="csrf-token"]')?.content || "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化本地时间为 MM-DD HH:mm,作为刚发放记录的临时展示时间。
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function currentRewardTimestamp() {
|
||||
const now = new Date();
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(now.getDate()).padStart(2, "0");
|
||||
const hour = String(now.getHours()).padStart(2, "0");
|
||||
const minute = String(now.getMinutes()).padStart(2, "0");
|
||||
|
||||
return `${month}-${day} ${hour}:${minute}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建职务奖励金币弹窗 Alpine 组件。
|
||||
*
|
||||
* @returns {Record<string, any>}
|
||||
*/
|
||||
export function rewardModal() {
|
||||
return {
|
||||
show: false,
|
||||
targetUsername: "",
|
||||
amount: "",
|
||||
sending: false,
|
||||
loading: false,
|
||||
quota: emptyRewardQuota(),
|
||||
|
||||
/**
|
||||
* 格式化额度数值。
|
||||
*
|
||||
* @param {number|null} value 额度值
|
||||
* @returns {string}
|
||||
*/
|
||||
fmt(value) {
|
||||
if (value === null) {
|
||||
return "不限";
|
||||
}
|
||||
|
||||
if (value === 0) {
|
||||
return "—";
|
||||
}
|
||||
|
||||
return `${value.toLocaleString()} 金币`;
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭奖励弹窗并同步关闭用户名片弹窗。
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
closeRelatedModals() {
|
||||
this.show = false;
|
||||
|
||||
const userModalElement = document.getElementById("user-modal-container");
|
||||
if (!window.Alpine || !userModalElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const userModalData = window.Alpine.$data(userModalElement);
|
||||
if (userModalData) {
|
||||
userModalData.showUserModal = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开奖励弹窗并加载当前额度。
|
||||
*
|
||||
* @param {string} username 目标用户名
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async open(username) {
|
||||
this.targetUsername = username;
|
||||
this.amount = "";
|
||||
this.sending = false;
|
||||
this.loading = true;
|
||||
this.show = true;
|
||||
|
||||
try {
|
||||
const response = await fetch(window.chatContext.rewardQuotaUrl, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
});
|
||||
this.quota = await response.json();
|
||||
if (!this.quota.recent_rewards) {
|
||||
this.quota.recent_rewards = [];
|
||||
}
|
||||
} catch (error) {
|
||||
this.quota = emptyRewardQuota();
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交奖励金币发放。
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async send() {
|
||||
if (this.sending) {
|
||||
return;
|
||||
}
|
||||
|
||||
const amount = Number.parseInt(this.amount, 10);
|
||||
if (!amount || amount <= 0) {
|
||||
window.chatDialog.alert("请输入有效金额", "提示", "#f59e0b");
|
||||
return;
|
||||
}
|
||||
|
||||
const maxOnce = window.chatContext?.myMaxReward;
|
||||
if (maxOnce === 0) {
|
||||
window.chatDialog.alert("你的职务没有奖励发放权限", "无权限", "#cc4444");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxOnce > 0 && amount > maxOnce) {
|
||||
window.chatDialog.alert(`超出单次上限 ${maxOnce} 金币`, "超出上限", "#cc4444");
|
||||
return;
|
||||
}
|
||||
|
||||
this.sending = true;
|
||||
|
||||
try {
|
||||
const response = await fetch(window.chatContext.rewardUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-TOKEN": csrfToken(),
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: this.targetUsername,
|
||||
room_id: window.chatContext.roomId,
|
||||
amount,
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === "success") {
|
||||
this.recordRewardSuccess(amount);
|
||||
this.closeRelatedModals();
|
||||
window.chatDialog.alert(data.message, "🎉 奖励发放成功", "#d97706");
|
||||
return;
|
||||
}
|
||||
|
||||
window.chatDialog.alert(data.message || "发放失败", "操作失败", "#cc4444");
|
||||
} catch (error) {
|
||||
window.chatDialog.alert("网络异常,请稍后重试", "错误", "#cc4444");
|
||||
}
|
||||
|
||||
this.sending = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* 本地更新额度和最近发放记录。
|
||||
*
|
||||
* @param {number} amount 发放金额
|
||||
* @returns {void}
|
||||
*/
|
||||
recordRewardSuccess(amount) {
|
||||
this.quota.today_sent += amount;
|
||||
|
||||
if (this.quota.daily_remaining !== null) {
|
||||
this.quota.daily_remaining = Math.max(0, this.quota.daily_remaining - amount);
|
||||
}
|
||||
|
||||
this.quota.recent_rewards.unshift({
|
||||
target: this.targetUsername,
|
||||
amount,
|
||||
created_at: currentRewardTimestamp(),
|
||||
});
|
||||
|
||||
if (this.quota.recent_rewards.length > 10) {
|
||||
this.quota.recent_rewards.pop();
|
||||
}
|
||||
|
||||
this.amount = "";
|
||||
this.sending = false;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开奖励金币独立弹窗。
|
||||
@@ -25,5 +239,6 @@ export function bindRewardModalControls() {
|
||||
return;
|
||||
}
|
||||
|
||||
window.rewardModal = rewardModal;
|
||||
window.openRewardModal = openRewardModal;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ export function userCardComponent() {
|
||||
selectedGiftId: giftDefaults.defaultGiftId,
|
||||
giftCount: 1,
|
||||
sendingGift: false,
|
||||
showGiftPanel: false,
|
||||
showGiftGoldPanel: false,
|
||||
giftGoldAmount: "",
|
||||
giftGoldSending: false,
|
||||
|
||||
// 职务奖励金币
|
||||
rewardAmount: 0,
|
||||
@@ -518,6 +522,55 @@ export function userCardComponent() {
|
||||
this.sendingGift = false;
|
||||
},
|
||||
|
||||
/** 切换礼物面板,和赠送金币面板互斥显示 */
|
||||
toggleGiftPanel() {
|
||||
this.showGiftPanel = !this.showGiftPanel;
|
||||
this.showGiftGoldPanel = false;
|
||||
},
|
||||
|
||||
/** 切换赠送金币面板,和礼物面板互斥显示 */
|
||||
toggleGiftGoldPanel() {
|
||||
this.showGiftGoldPanel = !this.showGiftGoldPanel;
|
||||
this.showGiftPanel = false;
|
||||
},
|
||||
|
||||
/** 给用户赠送自己的金币 */
|
||||
async sendGiftGold() {
|
||||
const amount = Number.parseInt(this.giftGoldAmount, 10);
|
||||
if (this.giftGoldSending || !amount || amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.giftGoldSending = true;
|
||||
|
||||
try {
|
||||
const response = await fetch("/gift/gold", {
|
||||
method: "POST",
|
||||
headers: this._headers(),
|
||||
body: JSON.stringify({
|
||||
to_user: this.userInfo.username,
|
||||
room_id: window.chatContext.roomId,
|
||||
amount,
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === "success") {
|
||||
window.chatContext.myGold = data.data?.my_jjb ?? window.chatContext.myGold;
|
||||
this.showGiftGoldPanel = false;
|
||||
this.giftGoldAmount = "";
|
||||
this.$alert(data.message, "赠送成功 💝", "#d97706");
|
||||
return;
|
||||
}
|
||||
|
||||
this.$alert(data.message, "赠送失败", "#cc4444");
|
||||
} catch (error) {
|
||||
this.$alert("网络异常", "错误", "#cc4444");
|
||||
}
|
||||
|
||||
this.giftGoldSending = false;
|
||||
},
|
||||
|
||||
/** 职务奖励:向用户发放金币(凭空产生,记入履职记录) */
|
||||
async sendReward() {
|
||||
if (this.sendingReward) return;
|
||||
|
||||
Reference in New Issue
Block a user