迁移婚礼弹窗组件脚本
This commit is contained in:
@@ -105,6 +105,8 @@ export {
|
|||||||
marriageProposeModal,
|
marriageProposeModal,
|
||||||
openProposeModal,
|
openProposeModal,
|
||||||
openWeddingSetupModal,
|
openWeddingSetupModal,
|
||||||
|
weddingEnvelopeModal,
|
||||||
|
weddingSetupModal,
|
||||||
} from "./chat-room/marriage-modals.js";
|
} from "./chat-room/marriage-modals.js";
|
||||||
export { bindToolbarControls, runFeatureShortcut, runToolbarAction } from "./chat-room/toolbar.js";
|
export { bindToolbarControls, runFeatureShortcut, runToolbarAction } from "./chat-room/toolbar.js";
|
||||||
export { bindUserCardControls, userCardComponent } from "./chat-room/user-card.js";
|
export { bindUserCardControls, userCardComponent } from "./chat-room/user-card.js";
|
||||||
@@ -288,6 +290,8 @@ import {
|
|||||||
marriageProposeModal,
|
marriageProposeModal,
|
||||||
openProposeModal,
|
openProposeModal,
|
||||||
openWeddingSetupModal,
|
openWeddingSetupModal,
|
||||||
|
weddingEnvelopeModal,
|
||||||
|
weddingSetupModal,
|
||||||
} from "./chat-room/marriage-modals.js";
|
} from "./chat-room/marriage-modals.js";
|
||||||
import { bindToolbarControls, runFeatureShortcut, runToolbarAction } from "./chat-room/toolbar.js";
|
import { bindToolbarControls, runFeatureShortcut, runToolbarAction } from "./chat-room/toolbar.js";
|
||||||
import { bindUserCardControls, userCardComponent } from "./chat-room/user-card.js";
|
import { bindUserCardControls, userCardComponent } from "./chat-room/user-card.js";
|
||||||
@@ -566,6 +570,8 @@ if (typeof window !== "undefined") {
|
|||||||
openMarriageStatusModal,
|
openMarriageStatusModal,
|
||||||
openProposeModal,
|
openProposeModal,
|
||||||
openWeddingSetupModal,
|
openWeddingSetupModal,
|
||||||
|
weddingEnvelopeModal,
|
||||||
|
weddingSetupModal,
|
||||||
renderMarriedList,
|
renderMarriedList,
|
||||||
renderMarriageStatus,
|
renderMarriageStatus,
|
||||||
switchMarriageTab,
|
switchMarriageTab,
|
||||||
@@ -750,6 +756,8 @@ if (typeof window !== "undefined") {
|
|||||||
window.marriageProposeModal = marriageProposeModal;
|
window.marriageProposeModal = marriageProposeModal;
|
||||||
window.openProposeModal = openProposeModal;
|
window.openProposeModal = openProposeModal;
|
||||||
window.openWeddingSetupModal = openWeddingSetupModal;
|
window.openWeddingSetupModal = openWeddingSetupModal;
|
||||||
|
window.weddingEnvelopeModal = weddingEnvelopeModal;
|
||||||
|
window.weddingSetupModal = weddingSetupModal;
|
||||||
window.renderMarriedList = renderMarriedList;
|
window.renderMarriedList = renderMarriedList;
|
||||||
window.renderMarriageStatus = renderMarriageStatus;
|
window.renderMarriageStatus = renderMarriageStatus;
|
||||||
window.switchMarriageTab = switchMarriageTab;
|
window.switchMarriageTab = switchMarriageTab;
|
||||||
|
|||||||
@@ -530,6 +530,180 @@ export function divorceRequestModal() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建婚礼设置弹窗 Alpine 数据,负责选择婚礼档位并提交举办请求。
|
||||||
|
*
|
||||||
|
* @returns {Record<string, any>}
|
||||||
|
*/
|
||||||
|
export function weddingSetupModal() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
marriageId: null,
|
||||||
|
tiers: [],
|
||||||
|
selectedTier: null,
|
||||||
|
payBy: "groom",
|
||||||
|
loading: false,
|
||||||
|
sending: false,
|
||||||
|
error: "",
|
||||||
|
|
||||||
|
get myCost() {
|
||||||
|
if (!this.selectedTier) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.payBy === "split" ? Math.ceil(this.selectedTier.amount / 2) : this.selectedTier.amount;
|
||||||
|
},
|
||||||
|
|
||||||
|
async open(marriageId) {
|
||||||
|
this.marriageId = marriageId;
|
||||||
|
this.selectedTier = null;
|
||||||
|
this.payBy = "groom";
|
||||||
|
this.error = "";
|
||||||
|
this.loading = true;
|
||||||
|
this.show = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(window.chatContext.marriage.weddingTiersUrl, {
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.status === "success") {
|
||||||
|
this.tiers = data.tiers;
|
||||||
|
|
||||||
|
if (this.tiers.length > 0) {
|
||||||
|
this.selectedTier = this.tiers[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
this.tiers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.show = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
async doSetup() {
|
||||||
|
if (this.sending || !this.selectedTier) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.error = "";
|
||||||
|
this.sending = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 当前产品只支持立即举办,前端固定 ceremony_type,避免保留无效时间选择状态。
|
||||||
|
const body = {
|
||||||
|
tier_id: this.selectedTier.id,
|
||||||
|
payer_type: this.payBy,
|
||||||
|
ceremony_type: "immediate",
|
||||||
|
room_id: window.chatContext.roomId,
|
||||||
|
};
|
||||||
|
const response = await fetch(window.chatContext.marriage.weddingSetupUrl(this.marriageId), {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
"X-CSRF-TOKEN": document.querySelector("meta[name=csrf-token]").content,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.status === "success") {
|
||||||
|
this.close();
|
||||||
|
window.chatDialog?.alert("🎊 婚礼已开始!红包正在分发给在线用户…", "设置成功", "#f59e0b");
|
||||||
|
} else {
|
||||||
|
this.error = data.message || "设置失败";
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
this.error = "网络异常,请稍后重试";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sending = false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建婚礼红包弹窗 Alpine 数据,负责展示和领取婚礼红包。
|
||||||
|
*
|
||||||
|
* @returns {Record<string, any>}
|
||||||
|
*/
|
||||||
|
export function weddingEnvelopeModal() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
marriageId: null,
|
||||||
|
ceremonyId: null,
|
||||||
|
title: "",
|
||||||
|
subTitle: "",
|
||||||
|
claimed: false,
|
||||||
|
claiming: false,
|
||||||
|
claimedAmount: 0,
|
||||||
|
|
||||||
|
open(detail) {
|
||||||
|
this.marriageId = detail.marriage_id;
|
||||||
|
this.ceremonyId = detail.ceremony_id;
|
||||||
|
const groomName = detail.groom_name ?? detail.user?.username ?? "??";
|
||||||
|
const brideName = detail.bride_name ?? detail.partner?.username ?? "??";
|
||||||
|
|
||||||
|
this.title = `${groomName} × ${brideName} 婚礼红包`;
|
||||||
|
this.subTitle = detail.tier_name ? `【${detail.tier_name}】普天同庆` : "婚礼庆典红包";
|
||||||
|
this.claimed = false;
|
||||||
|
this.claimedAmount = 0;
|
||||||
|
this.show = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.show = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
async doClaim() {
|
||||||
|
if (this.claiming || this.claimed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.claiming = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/wedding/ceremony/${this.ceremonyId}/claim`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json",
|
||||||
|
"X-CSRF-TOKEN": document.querySelector("meta[name=csrf-token]").content,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
ceremony_id: this.ceremonyId,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.ok) {
|
||||||
|
this.claimed = true;
|
||||||
|
this.claimedAmount = data.amount || 0;
|
||||||
|
} else {
|
||||||
|
window.chatDialog?.alert(data.message || "领取失败", "提示", "#f59e0b");
|
||||||
|
|
||||||
|
// 已领取或已过期时同步锁定按钮,避免用户重复提交同一个红包。
|
||||||
|
if (data.message?.includes("已领取") || data.message?.includes("已过期")) {
|
||||||
|
this.claimed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
window.chatDialog?.alert("网络异常", "错误", "#cc4444");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.claiming = false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取 Alpine 组件数据,避免直接访问 Alpine 私有字段。
|
* 读取 Alpine 组件数据,避免直接访问 Alpine 私有字段。
|
||||||
*
|
*
|
||||||
@@ -738,6 +912,8 @@ export function bindMarriageModalControls() {
|
|||||||
window.marriageProposeModal = marriageProposeModal;
|
window.marriageProposeModal = marriageProposeModal;
|
||||||
window.openProposeModal = openProposeModal;
|
window.openProposeModal = openProposeModal;
|
||||||
window.openWeddingSetupModal = openWeddingSetupModal;
|
window.openWeddingSetupModal = openWeddingSetupModal;
|
||||||
|
window.weddingEnvelopeModal = weddingEnvelopeModal;
|
||||||
|
window.weddingSetupModal = weddingSetupModal;
|
||||||
|
|
||||||
bindMarriageModalEvents();
|
bindMarriageModalEvents();
|
||||||
bindMarriageModalBootstrap();
|
bindMarriageModalBootstrap();
|
||||||
|
|||||||
@@ -680,154 +680,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{{-- ═══════════ Alpine.js 组件脚本 ═══════════ --}}
|
|
||||||
<script>
|
|
||||||
function weddingSetupModal() {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
marriageId: null,
|
|
||||||
tiers: [],
|
|
||||||
selectedTier: null,
|
|
||||||
payBy: 'groom',
|
|
||||||
loading: false,
|
|
||||||
sending: false,
|
|
||||||
error: '',
|
|
||||||
|
|
||||||
|
|
||||||
get myCost() {
|
|
||||||
if (!this.selectedTier) return 0;
|
|
||||||
return this.payBy === 'split' ?
|
|
||||||
Math.ceil(this.selectedTier.amount / 2) :
|
|
||||||
this.selectedTier.amount;
|
|
||||||
},
|
|
||||||
|
|
||||||
async open(marriageId) {
|
|
||||||
this.marriageId = marriageId;
|
|
||||||
this.selectedTier = null;
|
|
||||||
this.payBy = 'groom';
|
|
||||||
this.error = '';
|
|
||||||
this.loading = true;
|
|
||||||
this.show = true;
|
|
||||||
try {
|
|
||||||
const res = await fetch(window.chatContext.marriage.weddingTiersUrl, {
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const data = await res.json();
|
|
||||||
if (data.status === 'success') {
|
|
||||||
this.tiers = data.tiers;
|
|
||||||
if (this.tiers.length > 0) this.selectedTier = this.tiers[0];
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
this.tiers = [];
|
|
||||||
}
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.show = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
async doSetup() {
|
|
||||||
if (this.sending || !this.selectedTier) return;
|
|
||||||
this.error = '';
|
|
||||||
this.sending = true;
|
|
||||||
try {
|
|
||||||
// 固定使用立即举办,不再需要用户选择时间
|
|
||||||
const body = {
|
|
||||||
tier_id: this.selectedTier.id,
|
|
||||||
payer_type: this.payBy,
|
|
||||||
ceremony_type: 'immediate',
|
|
||||||
room_id: window.chatContext.roomId,
|
|
||||||
};
|
|
||||||
const res = await fetch(window.chatContext.marriage.weddingSetupUrl(this.marriageId), {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
});
|
|
||||||
const data = await res.json();
|
|
||||||
if (data.status === 'success') {
|
|
||||||
this.close();
|
|
||||||
window.chatDialog?.alert('🎊 婚礼已开始!红包正在分发给在线用户…', '设置成功', '#f59e0b');
|
|
||||||
} else {
|
|
||||||
this.error = data.message || '设置失败';
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
this.error = '网络异常,请稍后重试';
|
|
||||||
}
|
|
||||||
this.sending = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 婚礼红包弹窗组件
|
|
||||||
*/
|
|
||||||
function weddingEnvelopeModal() {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
marriageId: null,
|
|
||||||
ceremonyId: null,
|
|
||||||
title: '',
|
|
||||||
subTitle: '',
|
|
||||||
claimed: false,
|
|
||||||
claiming: false,
|
|
||||||
claimedAmount: 0,
|
|
||||||
|
|
||||||
open(detail) {
|
|
||||||
this.marriageId = detail.marriage_id;
|
|
||||||
this.ceremonyId = detail.ceremony_id;
|
|
||||||
// 兼容两种字段命名:groom_name/bride_name 或 user.username/partner.username
|
|
||||||
const groomName = detail.groom_name ?? detail.user?.username ?? '??';
|
|
||||||
const brideName = detail.bride_name ?? detail.partner?.username ?? '??';
|
|
||||||
this.title = `${groomName} × ${brideName} 婚礼红包`;
|
|
||||||
this.subTitle = detail.tier_name ? `【${detail.tier_name}】普天同庆` : '婚礼庆典红包';
|
|
||||||
this.claimed = false;
|
|
||||||
this.claimedAmount = 0;
|
|
||||||
this.show = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.show = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
async doClaim() {
|
|
||||||
if (this.claiming || this.claimed) return;
|
|
||||||
this.claiming = true;
|
|
||||||
try {
|
|
||||||
// 正确路由:/wedding/ceremony/{ceremonyId}/claim
|
|
||||||
const res = await fetch(`/wedding/ceremony/${this.ceremonyId}/claim`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
ceremony_id: this.ceremonyId
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const data = await res.json();
|
|
||||||
if (data.ok) {
|
|
||||||
this.claimed = true;
|
|
||||||
this.claimedAmount = data.amount || 0;
|
|
||||||
} else {
|
|
||||||
window.chatDialog?.alert(data.message || '领取失败', '提示', '#f59e0b');
|
|
||||||
if (data.message?.includes('已领取') || data.message?.includes('已过期')) {
|
|
||||||
this.claimed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
window.chatDialog?.alert('网络异常', '错误', '#cc4444');
|
|
||||||
}
|
|
||||||
this.claiming = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user