Admin/MarriageManagerController:
- index() 总览统计卡片
- list() 婚姻列表(筛选/强制离婚/取消求婚)
- proposals() 求婚记录
- ceremonies() 婚礼红包记录
- claimDetail() 红包领取明细
- intimacyLogs() 亲密度日志(来源筛选)
- configs/updateConfigs 参数配置(批量保存)
- tiers/updateTier 婚礼档位管理
Views(7个页面):admin/marriages/{index|list|configs|tiers|ceremonies|claim-detail|proposals|intimacy-logs}
侧边栏:superlevel 区块新增「💒 婚姻管理」入口
250 lines
8.0 KiB
PHP
250 lines
8.0 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 文件功能:后台婚姻系统管理控制器
|
||
*
|
||
* 提供总览统计、婚姻/求婚明细查询、婚礼档位管理、
|
||
* 参数配置、亲密度日志审计、强制离婚等管理操作。
|
||
*
|
||
* @author ChatRoom Laravel
|
||
*
|
||
* @version 1.0.0
|
||
*/
|
||
|
||
namespace App\Http\Controllers\Admin;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\Marriage;
|
||
use App\Models\MarriageIntimacyLog;
|
||
use App\Models\WeddingCeremony;
|
||
use App\Models\WeddingEnvelopeClaim;
|
||
use App\Models\WeddingTier;
|
||
use App\Services\MarriageConfigService;
|
||
use App\Services\MarriageService;
|
||
use Illuminate\Http\RedirectResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\View\View;
|
||
|
||
class MarriageManagerController extends Controller
|
||
{
|
||
public function __construct(
|
||
private readonly MarriageConfigService $config,
|
||
private readonly MarriageService $marriageService,
|
||
) {}
|
||
|
||
/**
|
||
* 婚姻管理总览(统计卡片 + 最近记录)。
|
||
*/
|
||
public function index(): View
|
||
{
|
||
$stats = [
|
||
'total_married' => Marriage::where('status', 'married')->count(),
|
||
'total_pending' => Marriage::where('status', 'pending')->count(),
|
||
'total_divorced' => Marriage::where('status', 'divorced')->count(),
|
||
'total_weddings' => WeddingCeremony::whereIn('status', ['active', 'completed'])->count(),
|
||
'total_envelopes' => WeddingEnvelopeClaim::sum('amount'),
|
||
'claimed_amount' => WeddingEnvelopeClaim::where('claimed', true)->sum('amount'),
|
||
];
|
||
|
||
$recentMarriages = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
|
||
->where('status', 'married')
|
||
->orderByDesc('married_at')
|
||
->limit(10)
|
||
->get();
|
||
|
||
$recentDivorces = Marriage::with(['user:id,username', 'partner:id,username'])
|
||
->where('status', 'divorced')
|
||
->orderByDesc('divorced_at')
|
||
->limit(8)
|
||
->get();
|
||
|
||
return view('admin.marriages.index', compact('stats', 'recentMarriages', 'recentDivorces'));
|
||
}
|
||
|
||
/**
|
||
* 婚姻列表(支持按状态/用户名筛选)。
|
||
*/
|
||
public function list(Request $request): View
|
||
{
|
||
$query = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
|
||
->orderByDesc('id');
|
||
|
||
if ($status = $request->get('status')) {
|
||
$query->where('status', $status);
|
||
}
|
||
if ($search = $request->get('search')) {
|
||
$query->where(function ($q) use ($search) {
|
||
$q->whereHas('user', fn ($u) => $u->where('username', 'like', "%{$search}%"))
|
||
->orWhereHas('partner', fn ($u) => $u->where('username', 'like', "%{$search}%"));
|
||
});
|
||
}
|
||
|
||
$marriages = $query->paginate(20)->withQueryString();
|
||
|
||
return view('admin.marriages.list', compact('marriages'));
|
||
}
|
||
|
||
/**
|
||
* 求婚记录列表(含 pending/expired/rejected)。
|
||
*/
|
||
public function proposals(Request $request): View
|
||
{
|
||
$proposals = Marriage::with(['user:id,username', 'partner:id,username', 'ringItem:id,name,icon'])
|
||
->whereIn('status', ['pending', 'expired', 'rejected'])
|
||
->orderByDesc('proposed_at')
|
||
->paginate(20)
|
||
->withQueryString();
|
||
|
||
return view('admin.marriages.proposals', compact('proposals'));
|
||
}
|
||
|
||
/**
|
||
* 婚礼红包记录。
|
||
*/
|
||
public function ceremonies(Request $request): View
|
||
{
|
||
$ceremonies = WeddingCeremony::with([
|
||
'marriage.user:id,username',
|
||
'marriage.partner:id,username',
|
||
'tier:id,name,tier,icon',
|
||
])
|
||
->orderByDesc('id')
|
||
->paginate(20)
|
||
->withQueryString();
|
||
|
||
return view('admin.marriages.ceremonies', compact('ceremonies'));
|
||
}
|
||
|
||
/**
|
||
* 红包领取明细(某场婚礼)。
|
||
*/
|
||
public function claimDetail(WeddingCeremony $ceremony): View
|
||
{
|
||
$ceremony->load(['marriage.user:id,username', 'marriage.partner:id,username', 'tier:id,name,icon']);
|
||
|
||
$claims = WeddingEnvelopeClaim::with('user:id,username,headface')
|
||
->where('ceremony_id', $ceremony->id)
|
||
->orderBy('amount', 'desc')
|
||
->paginate(30);
|
||
|
||
return view('admin.marriages.claim-detail', compact('ceremony', 'claims'));
|
||
}
|
||
|
||
/**
|
||
* 亲密度日志列表(支持按用户筛选)。
|
||
*/
|
||
public function intimacyLogs(Request $request): View
|
||
{
|
||
$query = MarriageIntimacyLog::with(['marriage.user:id,username', 'marriage.partner:id,username'])
|
||
->orderByDesc('id');
|
||
|
||
if ($search = $request->get('search')) {
|
||
$query->whereHas('marriage', function ($q) use ($search) {
|
||
$q->whereHas('user', fn ($u) => $u->where('username', 'like', "%{$search}%"))
|
||
->orWhereHas('partner', fn ($u) => $u->where('username', 'like', "%{$search}%"));
|
||
});
|
||
}
|
||
if ($source = $request->get('source')) {
|
||
$query->where('source', $source);
|
||
}
|
||
|
||
$logs = $query->paginate(30)->withQueryString();
|
||
|
||
return view('admin.marriages.intimacy-logs', compact('logs'));
|
||
}
|
||
|
||
/**
|
||
* 参数配置页面(读取所有分组配置)。
|
||
*/
|
||
public function configs(): View
|
||
{
|
||
$groups = $this->config->allGrouped();
|
||
|
||
return view('admin.marriages.configs', compact('groups'));
|
||
}
|
||
|
||
/**
|
||
* 批量保存参数配置。
|
||
*/
|
||
public function updateConfigs(Request $request): RedirectResponse
|
||
{
|
||
$data = $request->validate([
|
||
'configs' => 'required|array',
|
||
'configs.*' => 'required|integer',
|
||
]);
|
||
|
||
$this->config->batchSet($data['configs']);
|
||
|
||
return redirect()->route('admin.marriages.configs')->with('success', '婚姻参数配置已保存!');
|
||
}
|
||
|
||
/**
|
||
* 婚礼档位配置页面。
|
||
*/
|
||
public function tiers(): View
|
||
{
|
||
$tiers = WeddingTier::orderBy('tier')->get();
|
||
|
||
return view('admin.marriages.tiers', compact('tiers'));
|
||
}
|
||
|
||
/**
|
||
* 更新婚礼档位。
|
||
*/
|
||
public function updateTier(Request $request, WeddingTier $tier): RedirectResponse
|
||
{
|
||
$data = $request->validate([
|
||
'name' => 'required|string|max:30',
|
||
'icon' => 'required|string|max:20',
|
||
'amount' => 'required|integer|min:1',
|
||
'description' => 'nullable|string|max:100',
|
||
'is_active' => 'boolean',
|
||
]);
|
||
|
||
$data['is_active'] = $request->boolean('is_active', true);
|
||
$tier->update($data);
|
||
|
||
return redirect()->route('admin.marriages.tiers')->with('success', "档位【{$tier->name}】已更新!");
|
||
}
|
||
|
||
/**
|
||
* 管理员强制离婚。
|
||
*/
|
||
public function forceDissolve(Request $request, Marriage $marriage): RedirectResponse
|
||
{
|
||
$data = $request->validate([
|
||
'admin_note' => 'required|string|max:200',
|
||
]);
|
||
|
||
if ($marriage->status !== 'married') {
|
||
return back()->with('error', '该婚姻不是已婚状态,无法操作。');
|
||
}
|
||
|
||
$admin = $request->user();
|
||
$result = $this->marriageService->forceDissolve($marriage, $admin, true);
|
||
|
||
// 写入管理员备注
|
||
$marriage->update(['admin_note' => $data['admin_note']]);
|
||
|
||
$msg = $result['ok'] ? '强制离婚已完成。' : $result['message'];
|
||
$type = $result['ok'] ? 'success' : 'error';
|
||
|
||
return back()->with($type, $msg);
|
||
}
|
||
|
||
/**
|
||
* 管理员取消求婚(释放戒指 → 退还状态 active)。
|
||
*/
|
||
public function cancelProposal(Request $request, Marriage $marriage): RedirectResponse
|
||
{
|
||
if ($marriage->status !== 'pending') {
|
||
return back()->with('error', '该求婚不是进行中状态,无法取消。');
|
||
}
|
||
|
||
$this->marriageService->expireProposal($marriage);
|
||
$marriage->update(['admin_note' => '管理员手动取消求婚:'.($request->input('reason', ''))]);
|
||
|
||
return back()->with('success', '求婚已取消,戒指标记遗失。');
|
||
}
|
||
}
|