离婚流程全面升级:①发起方专属确认弹窗(含对方拒绝后果+魅力/金币惩罚实时值)②被申请方三选弹窗(同意/不同意/稍后)③不同意=强制离婚申请人赔一半金币④所有惩罚数值从后台实时查询

This commit is contained in:
2026-03-01 19:02:43 +08:00
parent 9b55b5558b
commit 84a4b42f31
7 changed files with 444 additions and 51 deletions
+3
View File
@@ -58,6 +58,8 @@ class MarriageDivorceRequested implements ShouldBroadcastNow
// 读取协议离婚魅力惩罚供前端展示
$penalty = (int) \App\Models\MarriageConfig::where('key', 'divorce_mutual_charm')->value('value');
// 读取强制离婚魅力惩罚(被拒=强制离婚时申请方受此惩罚)
$forcedPenalty = (int) \App\Models\MarriageConfig::where('key', 'divorce_forced_charm')->value('value');
return [
'marriage_id' => $this->marriage->id,
@@ -66,6 +68,7 @@ class MarriageDivorceRequested implements ShouldBroadcastNow
'timeout_hours' => 72,
'requested_at' => $this->marriage->divorce_requested_at,
'mutual_charm_penalty' => $penalty, // 协议离婚双方各扣魅力
'forced_charm_penalty' => $forcedPenalty, // 不同意→强制,申请方受此惩罚
];
}
@@ -20,6 +20,7 @@ use App\Events\MarriageProposed;
use App\Events\MarriageRejected;
use App\Models\Marriage;
use App\Models\UserPurchase;
use App\Services\MarriageConfigService;
use App\Services\MarriageService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -28,8 +29,23 @@ class MarriageController extends Controller
{
public function __construct(
private readonly MarriageService $marriage,
private readonly MarriageConfigService $config,
) {}
/**
* 获取离婚相关惩罚配置(供前端展示风险提示)。
* 返回协议离婚魅力惩罚、强制离婚魅力惩罚及各冷静期天数。
*/
public function divorceConfig(): JsonResponse
{
return response()->json([
'mutual_charm_penalty' => (int) $this->config->get('divorce_mutual_charm', 100),
'forced_charm_penalty' => (int) $this->config->get('divorce_forced_charm', 300),
'mutual_cooldown_days' => (int) $this->config->get('divorce_mutual_cooldown', 70),
'forced_cooldown_days' => (int) $this->config->get('divorce_forced_cooldown', 90),
]);
}
/**
* 获取当前用户的婚姻状态(名片/用户列表用)。
*/
@@ -221,4 +237,20 @@ class MarriageController extends Controller
return response()->json($result);
}
/**
* 拒绝协议离婚申请(被申请方选择不同意 = 视为强制离婚)。
* 申请人赔偿一半金币给对方,婚姻以 forced 类型解除。
*/
public function rejectDivorce(Request $request, Marriage $marriage): JsonResponse
{
$result = $this->marriage->rejectDivorce($marriage, $request->user());
if ($result['ok']) {
$marriage->refresh();
broadcast(new MarriageDivorced($marriage, 'forced'));
}
return response()->json($result);
}
}
+63
View File
@@ -304,6 +304,69 @@ class MarriageService
return ['ok' => true, 'message' => '协议离婚已完成。'];
}
/**
* 被申请方拒绝协议离婚申请(等同于强制离婚)。
*
* 规则:
* - 婚姻立即以 forced 类型解除
* - 申请人(divorcer)被扣除 divorce_forced_charm 点魅力作为惩罚
* - 申请人一半金币赔偿给被申请方
* - 申请人进入强制离婚冷静期
*
* @param Marriage $marriage 婚姻记录
* @param User $respondent 被申请方(拒绝者)
* @return array{ok: bool, message: string}
*/
public function rejectDivorce(Marriage $marriage, User $respondent): array
{
if ($marriage->status !== 'married' || $marriage->divorce_type !== 'mutual') {
return ['ok' => false, 'message' => '没有待处理的离婚申请。'];
}
if ($marriage->divorcer_id === $respondent->id) {
return ['ok' => false, 'message' => '不能拒绝自己发起的离婚申请。'];
}
if (! $marriage->involves($respondent->id)) {
return ['ok' => false, 'message' => '无权操作此婚姻。'];
}
// 申请方(被拒的一方)
$divorcer = $marriage->user_id === $marriage->divorcer_id
? $marriage->user
: $marriage->partner;
DB::transaction(function () use ($marriage, $divorcer, $respondent) {
$charmPenalty = $this->config->get('divorce_forced_charm', 300);
// 申请人扣魅力
$this->currency->change($divorcer, 'charm', -$charmPenalty, CurrencySource::DIVORCE_CHARM, '拒绝离婚时视为强制离婚,扣除魅力惩罚');
// 申请人一半金币赔偿给对方
$divorcerJjb = $divorcer->fresh()->jjb ?? 0;
if ($divorcerJjb > 0) {
$half = (int) floor($divorcerJjb / 2);
if ($half > 0) {
$this->currency->change($divorcer, 'gold', -$half, CurrencySource::FORCED_DIVORCE_TRANSFER, "协议离婚被拒,赔偿一半金币给 {$respondent->username}");
$this->currency->change($respondent, 'gold', $half, CurrencySource::FORCED_DIVORCE_TRANSFER, "对方协议离婚被拒,获得 {$divorcer->username} 一半金币赔偿");
}
}
// 更新婚姻为强制离婚
$marriage->update([
'status' => 'divorced',
'divorce_type' => 'forced',
'divorcer_id' => $divorcer->id,
'divorced_at' => now(),
'intimacy' => 0,
'level' => 1,
]);
});
$divorcerJjb = $divorcer->fresh()->jjb ?? 0;
$half = (int) floor(($divorcer->jjb ?? 0) / 2);
return ['ok' => true, 'message' => "你已拒绝离婚申请,视为强制离婚,{$divorcer->username} 赔偿了 {$half} 枚金币给你,婚姻已解除。"];
}
/**
* 强制离婚(单方立即生效,发起方金币全转对方)。
*
+2
View File
@@ -74,6 +74,8 @@
rejectUrl: (id) => `/marriage/${id}/reject`,
divorceUrl: (id) => `/marriage/${id}/divorce`,
confirmDivorceUrl: (id) => `/marriage/${id}/confirm-divorce`,
rejectDivorceUrl: (id) => `/marriage/${id}/reject-divorce`,
divorceConfigUrl: '/marriage/divorce-config',
weddingTiersUrl: "/wedding/tiers",
weddingSetupUrl: (id) => `/wedding/${id}/setup`,
claimEnvelopeUrl: (id, ceremonyId) => `/wedding/${id}/claim`,
@@ -340,6 +340,181 @@
</style>
{{-- ═══════════ 3.5. 发起离婚确认弹窗(发起方专用 + 后果说明) ═══════════ --}}
<div id="divorce-confirm-modal" x-data="divorceConfirmModal()" x-show="show" x-cloak>
<div x-transition
style="position:fixed; inset:0; background:rgba(10,14,21,.87); backdrop-filter:blur(3px);
z-index:9925; display:flex; align-items:center; justify-content:center; padding:16px;">
<div
style="width:480px; max-width:95vw; background:#1a1f2e; border:1px solid rgba(100,116,140,.3);
border-radius:24px; box-shadow:0 32px 80px rgba(0,0,0,.8); overflow:hidden;">
{{-- 头部 --}}
<div
style="padding:24px 28px 16px; background:linear-gradient(160deg,#252d3a,#1e2736); text-align:center;">
<div style="font-size:44px; margin-bottom:10px;">📄</div>
<div style="color:#f1f5f9; font-weight:bold; font-size:18px; margin-bottom:4px;">发起协议离婚申请</div>
<div style="color:#64748b; font-size:12px;">请仔细阅读以下后果,确认后再提交申请</div>
</div>
<div style="padding:16px 24px;">
{{-- 对方同意:协议离婚 --}}
<div
style="background:rgba(100,116,140,.08); border:1px solid rgba(100,116,140,.25); border-radius:12px; padding:12px 16px; margin-bottom:10px;">
<div style="color:#94a3b8; font-weight:bold; font-size:13px; margin-bottom:6px;"> 若对方同意(协议离婚)
</div>
<ul style="color:#94a3b8; font-size:12px; line-height:2; margin:0; padding-left:20px;">
<li>婚姻关系<strong style="color:#e2e8f0;">立即解除</strong>,亲密度清零</li>
<li>双方各被扣除 <strong style="color:#fca5a5;" x-text="mutualPenalty + ' 点魅力值'"></strong></li>
<li>双方进入 <strong style="color:#e2e8f0;" x-text="mutualCooldown + ' 天'"></strong>
离婚冷静期,期间无法再次结婚</li>
</ul>
</div>
{{-- 对方拒绝:强制离婚,自己赔钱 --}}
<div
style="background:rgba(239,68,68,.08); border:1px solid rgba(239,68,68,.3); border-radius:12px; padding:12px 16px; margin-bottom:16px;">
<div style="color:#fca5a5; font-weight:bold; font-size:13px; margin-bottom:6px;">⚠️
若对方拒绝(视为强制离婚,后果由你承担)</div>
<ul style="color:#94a3b8; font-size:12px; line-height:2; margin:0; padding-left:20px;">
<li>婚姻关系<strong style="color:#fca5a5;">立即强制解除</strong></li>
<li><strong style="color:#fca5a5;">你将被扣除 <span x-text="forcedPenalty"></span>
点魅力值</strong>作为惩罚</li>
<li><strong style="color:#fca5a5;">你当前一半的金币将赔偿给对方</strong></li>
<li>你进入 <strong style="color:#fca5a5;" x-text="forcedCooldown + ' 天'"></strong>
强制离婚冷静期,期间无法再次结婚</li>
</ul>
</div>
{{-- 操作按钮 --}}
<div style="display:flex; gap:10px; justify-content:center;">
<button x-on:click="doConfirm()" :disabled="acting"
style="flex:1; padding:12px 0; border-radius:12px; border:none; font-size:14px; font-weight:bold; cursor:pointer; transition:all .2s;
background:linear-gradient(135deg,#475569,#334155); color:#e2e8f0; box-shadow:0 4px 12px rgba(0,0,0,.3);"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
<span x-text="acting ? '发送中…' : '📄 确认发起申请'"></span>
</button>
<button x-on:click="close()" :disabled="acting"
style="flex:0 0 auto; padding:12px 24px; border-radius:12px; font-size:13px; cursor:pointer; transition:all .2s;
background:rgba(100,116,140,.12); border:1px solid rgba(100,116,140,.3); color:#64748b;"
onmouseover="this.style.background='rgba(100,116,140,.22)'"
onmouseout="this.style.background='rgba(100,116,140,.12)'">
取消
</button>
</div>
<div x-show="error" x-transition
style="display:none; margin-top:10px; background:rgba(239,68,68,.1); border:1px solid rgba(239,68,68,.3); border-radius:8px; padding:8px 12px; font-size:12px; color:#fca5a5; text-align:center;"
x-text="error"></div>
</div>
</div>
</div>
</div>
{{-- ═══════════ 3.6. 离婚申请通知弹窗(三选按钮 + 后果说明) ═══════════ --}}
<div id="divorce-request-modal" x-data="divorceRequestModal()" x-show="show" x-cloak>
<div x-transition
style="position:fixed; inset:0; background:rgba(10,14,21,.85); backdrop-filter:blur(3px);
z-index:9920; display:flex; align-items:center; justify-content:center; padding:16px;">
<div
style="width:480px; max-width:95vw; background:#1a1f2e; border:1px solid rgba(100,116,140,.3);
border-radius:24px; box-shadow:0 32px 80px rgba(0,0,0,.8); overflow:hidden;">
{{-- 头部 --}}
<div
style="padding:28px 28px 20px; background:linear-gradient(160deg,#252d3a,#1e2736); text-align:center;">
<div style="font-size:48px; margin-bottom:12px; animation:divorce-shake 0.7s ease 0.2s both;">💔</div>
<div style="color:#f1f5f9; font-weight:bold; font-size:19px; margin-bottom:6px;">收到离婚申请</div>
<div style="color:#94a3b8; font-size:14px; line-height:1.6;" x-text="initiatorName + ' 向你提出了协议离婚申请。'">
</div>
<div style="color:#64748b; font-size:12px; margin-top:4px;">请仔细阅读以下后果说明,做出你的选择:</div>
</div>
{{-- 后果说明区 --}}
<div style="padding:16px 24px;">
{{-- 同意后果 --}}
<div
style="background:rgba(239,68,68,.08); border:1px solid rgba(239,68,68,.25); border-radius:12px; padding:12px 16px; margin-bottom:10px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:6px;">
<span
style="background:#ef4444; border-radius:50%; width:22px; height:22px; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:bold; color:#fff; flex-shrink:0;"></span>
<span style="color:#fca5a5; font-weight:bold; font-size:13px;">同意离婚</span>
</div>
<ul style="color:#94a3b8; font-size:12px; line-height:2; margin:0; padding-left:30px;">
<li>婚姻关系<strong style="color:#fca5a5;">立即解除</strong>,所有亲密度清零</li>
<li>双方各被扣除 <strong style="color:#fca5a5;" x-text="mutualPenalty + ' 点魅力值'">? 点魅力值</strong>
</li>
<li>双方都将进入<strong style="color:#fca5a5;">离婚冷静期</strong>,期间无法再次结婚</li>
</ul>
</div>
{{-- 拒绝后果 --}}
<div
style="background:rgba(234,179,8,.08); border:1px solid rgba(234,179,8,.25); border-radius:12px; padding:12px 16px; margin-bottom:10px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:6px;">
<span
style="background:#ca8a04; border-radius:50%; width:22px; height:22px; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:bold; color:#fff; flex-shrink:0;"></span>
<span style="color:#fde68a; font-weight:bold; font-size:13px;">不同意(强制离婚)</span>
</div>
<ul style="color:#94a3b8; font-size:12px; line-height:2; margin:0; padding-left:30px;">
<li>视同<strong style="color:#fde68a;">强制离婚</strong>,婚姻<strong
style="color:#fde68a;">立即解除</strong></li>
<li>申请方被扣除大量魅力值作为<strong style="color:#fde68a;">惩罚</strong></li>
<li>申请方当前<strong style="color:#fde68a;">一半金币赔偿给你</strong>(入账到你账户)</li>
<li>申请方进入<strong style="color:#fde68a;">强制离婚冷静期</strong>,期间无法再次结婚</li>
</ul>
</div>
{{-- 取消(稍后处理) --}}
<div
style="background:rgba(100,116,140,.06); border:1px solid rgba(100,116,140,.2); border-radius:12px; padding:10px 16px; margin-bottom:16px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:4px;">
<span
style="background:#475569; border-radius:50%; width:22px; height:22px; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:bold; color:#fff; flex-shrink:0;"></span>
<span style="color:#94a3b8; font-weight:bold; font-size:13px;">稍后决定</span>
</div>
<ul style="color:#64748b; font-size:12px; line-height:2; margin:0; padding-left:30px;">
<li>关闭此弹窗,<strong style="color:#94a3b8;">暂不做决定</strong></li>
<li>下次登录或刷新页面时<strong style="color:#94a3b8;">仍会再次弹出</strong>提示</li>
<li>72 小时内若不处理,系统将<strong style="color:#94a3b8;">自动视为对方强制离婚</strong></li>
</ul>
</div>
{{-- 三个按钮 --}}
<div style="display:flex; gap:10px; justify-content:center;">
{{-- 同意 --}}
<button x-on:click="doAgree()" :disabled="acting"
style="flex:1; padding:12px 0; border-radius:12px; border:none; font-size:14px; font-weight:bold; cursor:pointer; transition:all .2s;
background:linear-gradient(135deg,#dc2626,#b91c1c); color:#fff; box-shadow:0 4px 12px rgba(220,38,38,.35);"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
<span x-text="acting ? '处理中…' : '✓ 同意离婚'"></span>
</button>
{{-- 拒绝 --}}
<button x-on:click="doReject()" :disabled="acting"
style="flex:1; padding:12px 0; border-radius:12px; border:none; font-size:14px; font-weight:bold; cursor:pointer; transition:all .2s;
background:linear-gradient(135deg,#d97706,#b45309); color:#fff; box-shadow:0 4px 12px rgba(217,119,6,.3);"
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
<span x-text="acting ? '处理中…' : '✕ 拒绝离婚'"></span>
</button>
{{-- 取消 --}}
<button x-on:click="close()" :disabled="acting"
style="flex:0 0 auto; padding:12px 20px; border-radius:12px; font-size:13px; cursor:pointer; transition:all .2s;
background:rgba(100,116,140,.15); border:1px solid rgba(100,116,140,.3); color:#94a3b8;"
onmouseover="this.style.background='rgba(100,116,140,.25)'"
onmouseout="this.style.background='rgba(100,116,140,.15)'">
稍后
</button>
</div>
<div x-show="error" x-transition
style="display:none; background:rgba(239,68,68,.1); border:1px solid rgba(239,68,68,.3); border-radius:8px; padding:8px 12px; margin-top:12px; font-size:12px; color:#fca5a5; text-align:center;"
x-text="error"></div>
</div>
</div>
</div>
</div>
{{-- ═══════════ 4. 婚礼设置弹窗 ═══════════ --}}
<div id="wedding-setup-modal" x-data="weddingSetupModal()" x-show="show" x-cloak>
<div
@@ -809,10 +984,150 @@
};
}
/**
* 发起离婚确认弹窗(发起方专用:展示双方结果 + 实时惩罚值)
*/
function divorceConfirmModal() {
return {
show: false,
marriageId: null,
mutualPenalty: 0,
forcedPenalty: 0,
mutualCooldown: 0,
forcedCooldown: 0,
acting: false,
error: '',
open(marriageId, config) {
this.marriageId = marriageId;
this.mutualPenalty = config.mutual_charm_penalty ?? 0;
this.forcedPenalty = config.forced_charm_penalty ?? 0;
this.mutualCooldown = config.mutual_cooldown_days ?? 0;
this.forcedCooldown = config.forced_cooldown_days ?? 0;
this.acting = false;
this.error = '';
this.show = true;
},
close() {
this.show = false;
},
/** 确认发起离婚申请 */
async doConfirm() {
if (this.acting) return;
this.acting = true;
this.error = '';
try {
const res = await fetch(window.chatContext.marriage.divorceUrl(this.marriageId), {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
}
});
const data = await res.json();
this.close();
if (data.ok) {
window.chatDialog?.alert(data.message, '申请已发出 📩', '#6b7280');
} else {
window.chatDialog?.alert(data.message || '操作失败', '错误', '#dc2626');
}
} catch (e) {
this.error = '网络请求失败,请重试。';
} finally {
this.acting = false;
}
}
};
}
/**
* 婚礼设置弹窗组件
* 离婚申请通知弹窗(被申请方专用:三选 + 真实惩罚值)
*/
function divorceRequestModal() {
return {
show: false,
marriageId: null,
initiatorName: '',
mutualPenalty: 0, // 同意后双方各扣魅力
forcedPenalty: 0, // 不同意后申请方被扣魅力
acting: false,
error: '',
open(detail) {
this.marriageId = detail.marriage_id;
this.initiatorName = detail.initiator_name ?? detail.divorcer_username ?? '对方';
this.mutualPenalty = detail.mutual_charm_penalty ?? 0;
this.forcedPenalty = detail.forced_charm_penalty ?? 0;
this.acting = false;
this.error = '';
this.show = true;
},
close() {
this.show = false;
},
/** 同意:协议离婚,双方各扣 mutualPenalty 魅力 */
async doAgree() {
if (this.acting) return;
this.acting = true;
this.error = '';
try {
const res = await fetch(window.chatContext.marriage.confirmDivorceUrl(this.marriageId), {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
},
body: JSON.stringify({
room_id: window.chatContext.roomId
})
});
const data = await res.json();
this.close();
window.chatDialog?.alert(data.message, data.ok ? '操作完成' : '失败', data.ok ? '#6b7280' :
'#cc4444');
} catch (e) {
this.error = '网络请求失败,请重试。';
} finally {
this.acting = false;
}
},
/** 不同意:视为强制离婚,申请方扣魅力 + 赔一半金币 */
async doReject() {
if (this.acting) return;
this.acting = true;
this.error = '';
try {
const res = await fetch(window.chatContext.marriage.rejectDivorceUrl(this.marriageId), {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
},
body: JSON.stringify({
room_id: window.chatContext.roomId
})
});
const data = await res.json();
this.close();
window.chatDialog?.alert(data.message, data.ok ? '已处理' : '失败', data.ok ? '#d97706' : '#cc4444');
} catch (e) {
this.error = '网络请求失败,请重试。';
} finally {
this.acting = false;
}
}
};
}
function weddingSetupModal() {
return {
show: false,
@@ -1085,38 +1400,15 @@
);
});
/** 接到协议离婚申请(私人频道,对方) */
/** 接到协议离婚申请(私人频道,对方)→ 打开专属三选弹窗 */
window.addEventListener('chat:divorce-requested', (e) => {
const {
initiator_name,
marriage_id,
mutual_charm_penalty
} = e.detail;
const penaltyTip = mutual_charm_penalty > 0 ?
`\n\n⚠️ 双方各将被扣除 ${mutual_charm_penalty} 点魅力值作为惩罚。` :
'';
window.chatDialog?.confirm(
`${initiator_name} 申请与你协议离婚,是否同意?${penaltyTip}`,
'离婚申请 💔'
).then(ok => {
if (!ok) return;
fetch(window.chatContext.marriage.confirmDivorceUrl(marriage_id), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
},
body: JSON.stringify({
room_id: window.chatContext.roomId
})
}).then(r => r.json()).then(data => {
window.chatDialog?.alert(data.message, data.status === 'success' ? '操作完成' :
'失败', data.status === 'success' ? '#6b7280' : '#cc4444');
});
});
const detail = e.detail;
const el = document.getElementById('divorce-request-modal');
if (el) Alpine.$data(el).open(detail);
});
/** 红包领取成功通知(私人频道) */
window.addEventListener('chat:envelope-claimed', (e) => {
const {
@@ -172,40 +172,37 @@
return;
},
/** 发起协议离婚 */
/** 发起协议离婚(先拉惩罚配置,再弹专属全屏确认弹窗) */
async doDivorce(marriageId) {
if (!marriageId) return;
this.showUserModal = false;
const confirmed = await window.chatDialog?.confirm(
'提出离婚后,对方将在私人频道收到通知。\n\n如果对方在 24 小时内未作决定,此申请将自动升级为“强制离婚”,并扣除发起方一定的魅力值作为单方面解除契约的惩罚。\n\n您确定要继续发起离婚申请吗?',
'发起离婚',
'#475569'
);
if (!confirmed) return;
window.chatDialog?.alert('请稍候…', '发送申请中', '#9ca3af');
// 从后台实时拉取最新惩罚配置
let divorceConfig = {
mutual_charm_penalty: 0,
forced_charm_penalty: 0,
mutual_cooldown_days: 0,
forced_cooldown_days: 0
};
try {
const res = await fetch(window.chatContext.marriage.divorceUrl(marriageId), {
method: 'POST',
const cfgRes = await fetch(window.chatContext.marriage.divorceConfigUrl, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content
'X-Requested-With': 'XMLHttpRequest'
}
});
const data = await res.json();
if (data.ok) {
window.chatDialog?.alert(data.message, '已发出', '#6b7280');
} else {
window.chatDialog?.alert(data.message || '操作失败', '错误', '#dc2626');
}
if (cfgRes.ok) divorceConfig = await cfgRes.json();
} catch (e) {
window.chatDialog?.alert('网络请求失败', '错误', '#dc2626');
/* 网络异常则使用默认值 */ }
// 打开专属离婚确认弹窗
const modal = document.getElementById('divorce-confirm-modal');
if (modal && window.Alpine) {
Alpine.$data(modal).open(marriageId, divorceConfig);
}
},
/** 获取用户资料 */
async fetchUser(username) {
try {
+4
View File
@@ -87,8 +87,12 @@ Route::middleware(['chat.auth'])->group(function () {
Route::post('/{marriage}/reject', [\App\Http\Controllers\MarriageController::class, 'reject'])->name('reject');
// 申请离婚(type: mutual|forced
Route::post('/{marriage}/divorce', [\App\Http\Controllers\MarriageController::class, 'divorce'])->name('divorce');
// 离婚惩罚配置查询(前端展示风险提示用)
Route::get('/divorce-config', [\App\Http\Controllers\MarriageController::class, 'divorceConfig'])->name('divorce-config');
// 确认协议离婚
Route::post('/{marriage}/confirm-divorce', [\App\Http\Controllers\MarriageController::class, 'confirmDivorce'])->name('confirm-divorce');
// 拒绝离婚申请(被申请方选择不同意→弹强制离婚)
Route::post('/{marriage}/reject-divorce', [\App\Http\Controllers\MarriageController::class, 'rejectDivorce'])->name('reject-divorce');
});
// ── 婚礼系统(前台)──────────────────────────────────────────────